package handlers

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/breakpilot/consent-service/internal/models"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// ========================================
// ADMIN ENDPOINTS - Cookie Categories
// ========================================

// AdminGetCookieCategories returns all cookie categories
func (h *Handler) AdminGetCookieCategories(c *gin.Context) {
	ctx := context.Background()

	rows, err := h.db.Pool.Query(ctx, `
		SELECT id, name, display_name_de, display_name_en, description_de, description_en,
		       is_mandatory, sort_order, is_active, created_at, updated_at
		FROM cookie_categories
		ORDER BY sort_order ASC
	`)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch categories"})
		return
	}
	defer rows.Close()

	var categories []models.CookieCategory
	for rows.Next() {
		var cat models.CookieCategory
		if err := rows.Scan(&cat.ID, &cat.Name, &cat.DisplayNameDE, &cat.DisplayNameEN,
			&cat.DescriptionDE, &cat.DescriptionEN, &cat.IsMandatory, &cat.SortOrder,
			&cat.IsActive, &cat.CreatedAt, &cat.UpdatedAt); err != nil {
			continue
		}
		categories = append(categories, cat)
	}

	c.JSON(http.StatusOK, gin.H{"categories": categories})
}

// AdminCreateCookieCategory creates a new cookie category
func (h *Handler) AdminCreateCookieCategory(c *gin.Context) {
	var req models.CreateCookieCategoryRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
		return
	}

	ctx := context.Background()

	var catID uuid.UUID
	err := h.db.Pool.QueryRow(ctx, `
		INSERT INTO cookie_categories (name, display_name_de, display_name_en, description_de, description_en, is_mandatory, sort_order)
		VALUES ($1, $2, $3, $4, $5, $6, $7)
		RETURNING id
	`, req.Name, req.DisplayNameDE, req.DisplayNameEN, req.DescriptionDE, req.DescriptionEN, req.IsMandatory, req.SortOrder).Scan(&catID)

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create category"})
		return
	}

	c.JSON(http.StatusCreated, gin.H{
		"message": "Cookie category created successfully",
		"id":      catID,
	})
}

// AdminUpdateCookieCategory updates a cookie category
func (h *Handler) AdminUpdateCookieCategory(c *gin.Context) {
	catID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid category ID"})
		return
	}

	var req struct {
		DisplayNameDE *string `json:"display_name_de"`
		DisplayNameEN *string `json:"display_name_en"`
		DescriptionDE *string `json:"description_de"`
		DescriptionEN *string `json:"description_en"`
		IsMandatory   *bool   `json:"is_mandatory"`
		SortOrder     *int    `json:"sort_order"`
		IsActive      *bool   `json:"is_active"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
		return
	}

	ctx := context.Background()

	result, err := h.db.Pool.Exec(ctx, `
		UPDATE cookie_categories
		SET display_name_de = COALESCE($2, display_name_de),
		    display_name_en = COALESCE($3, display_name_en),
		    description_de = COALESCE($4, description_de),
		    description_en = COALESCE($5, description_en),
		    is_mandatory = COALESCE($6, is_mandatory),
		    sort_order = COALESCE($7, sort_order),
		    is_active = COALESCE($8, is_active),
		    updated_at = NOW()
		WHERE id = $1
	`, catID, req.DisplayNameDE, req.DisplayNameEN, req.DescriptionDE, req.DescriptionEN,
		req.IsMandatory, req.SortOrder, req.IsActive)

	if err != nil || result.RowsAffected() == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "Category not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Cookie category updated successfully"})
}

// AdminDeleteCookieCategory soft-deletes a cookie category
func (h *Handler) AdminDeleteCookieCategory(c *gin.Context) {
	catID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid category ID"})
		return
	}

	ctx := context.Background()

	result, err := h.db.Pool.Exec(ctx, `
		UPDATE cookie_categories
		SET is_active = false, updated_at = NOW()
		WHERE id = $1
	`, catID)

	if err != nil || result.RowsAffected() == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "Category not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Cookie category deleted successfully"})
}

// ========================================
// ADMIN ENDPOINTS - Statistics & Audit
// ========================================

// GetConsentStats returns consent statistics
func (h *Handler) GetConsentStats(c *gin.Context) {
	ctx := context.Background()
	docType := c.Query("document_type")

	var stats models.ConsentStats

	// Total users
	h.db.Pool.QueryRow(ctx, `SELECT COUNT(*) FROM users`).Scan(&stats.TotalUsers)

	// Consented users (with active consent)
	query := `
		SELECT COUNT(DISTINCT uc.user_id)
		FROM user_consents uc
		JOIN document_versions dv ON uc.document_version_id = dv.id
		JOIN legal_documents ld ON dv.document_id = ld.id
		WHERE uc.consented = true AND uc.withdrawn_at IS NULL
	`
	if docType != "" {
		query += ` AND ld.type = $1`
		h.db.Pool.QueryRow(ctx, query, docType).Scan(&stats.ConsentedUsers)
	} else {
		h.db.Pool.QueryRow(ctx, query).Scan(&stats.ConsentedUsers)
	}

	// Calculate consent rate
	if stats.TotalUsers > 0 {
		stats.ConsentRate = float64(stats.ConsentedUsers) / float64(stats.TotalUsers) * 100
	}

	// Recent consents (last 7 days)
	h.db.Pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM user_consents
		WHERE consented = true AND consented_at > NOW() - INTERVAL '7 days'
	`).Scan(&stats.RecentConsents)

	// Recent withdrawals
	h.db.Pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM user_consents
		WHERE withdrawn_at IS NOT NULL AND withdrawn_at > NOW() - INTERVAL '7 days'
	`).Scan(&stats.RecentWithdrawals)

	c.JSON(http.StatusOK, stats)
}

// GetCookieStats returns cookie consent statistics
func (h *Handler) GetCookieStats(c *gin.Context) {
	ctx := context.Background()

	rows, err := h.db.Pool.Query(ctx, `
		SELECT cat.name,
		       COUNT(DISTINCT u.id) as total_users,
		       COUNT(DISTINCT CASE WHEN cc.consented = true THEN cc.user_id END) as consented_users
		FROM cookie_categories cat
		CROSS JOIN users u
		LEFT JOIN cookie_consents cc ON cat.id = cc.category_id AND u.id = cc.user_id
		WHERE cat.is_active = true
		GROUP BY cat.id, cat.name
		ORDER BY cat.sort_order
	`)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch stats"})
		return
	}
	defer rows.Close()

	var stats []models.CookieStats
	for rows.Next() {
		var s models.CookieStats
		if err := rows.Scan(&s.Category, &s.TotalUsers, &s.ConsentedUsers); err != nil {
			continue
		}
		if s.TotalUsers > 0 {
			s.ConsentRate = float64(s.ConsentedUsers) / float64(s.TotalUsers) * 100
		}
		stats = append(stats, s)
	}

	c.JSON(http.StatusOK, gin.H{"cookie_stats": stats})
}

// GetAuditLog returns audit log entries
func (h *Handler) GetAuditLog(c *gin.Context) {
	ctx := context.Background()

	// Pagination
	limit := 50
	offset := 0
	if l := c.Query("limit"); l != "" {
		if parsed, err := parseIntFromQuery(l); err == nil && parsed > 0 {
			limit = parsed
		}
	}
	if o := c.Query("offset"); o != "" {
		if parsed, err := parseIntFromQuery(o); err == nil && parsed >= 0 {
			offset = parsed
		}
	}

	// Filters
	userIDFilter := c.Query("user_id")
	actionFilter := c.Query("action")

	query := `
		SELECT al.id, al.user_id, al.action, al.entity_type, al.entity_id, al.details,
		       al.ip_address, al.user_agent, al.created_at, u.email
		FROM consent_audit_log al
		LEFT JOIN users u ON al.user_id = u.id
		WHERE 1=1
	`
	args := []interface{}{}
	argCount := 0

	if userIDFilter != "" {
		argCount++
		query += fmt.Sprintf(" AND al.user_id = $%d", argCount)
		args = append(args, userIDFilter)
	}
	if actionFilter != "" {
		argCount++
		query += fmt.Sprintf(" AND al.action = $%d", argCount)
		args = append(args, actionFilter)
	}

	query += fmt.Sprintf(" ORDER BY al.created_at DESC LIMIT $%d OFFSET $%d", argCount+1, argCount+2)
	args = append(args, limit, offset)

	rows, err := h.db.Pool.Query(ctx, query, args...)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch audit log"})
		return
	}
	defer rows.Close()

	var logs []map[string]interface{}
	for rows.Next() {
		var (
			id         uuid.UUID
			userIDPtr  *uuid.UUID
			action     string
			entityType *string
			entityID   *uuid.UUID
			details    *string
			ipAddress  *string
			userAgent  *string
			createdAt  time.Time
			email      *string
		)

		if err := rows.Scan(&id, &userIDPtr, &action, &entityType, &entityID, &details,
			&ipAddress, &userAgent, &createdAt, &email); err != nil {
			continue
		}

		logs = append(logs, map[string]interface{}{
			"id":          id,
			"user_id":     userIDPtr,
			"user_email":  email,
			"action":      action,
			"entity_type": entityType,
			"entity_id":   entityID,
			"details":     details,
			"ip_address":  ipAddress,
			"user_agent":  userAgent,
			"created_at":  createdAt,
		})
	}

	c.JSON(http.StatusOK, gin.H{"audit_log": logs})
}
