package handlers

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

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

// ========================================
// PUBLIC ENDPOINTS - Consent
// ========================================

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

	userID, err := middleware.GetUserID(c)
	if err != nil || userID == uuid.Nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
		return
	}

	versionID, err := uuid.Parse(req.VersionID)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid version ID"})
		return
	}

	ctx := context.Background()
	ipAddress := middleware.GetClientIP(c)
	userAgent := middleware.GetUserAgent(c)

	// Upsert consent
	var consentID uuid.UUID
	err = h.db.Pool.QueryRow(ctx, `
		INSERT INTO user_consents (user_id, document_version_id, consented, ip_address, user_agent)
		VALUES ($1, $2, $3, $4, $5)
		ON CONFLICT (user_id, document_version_id)
		DO UPDATE SET consented = $3, consented_at = NOW(), withdrawn_at = NULL
		RETURNING id
	`, userID, versionID, req.Consented, ipAddress, userAgent).Scan(&consentID)

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

	// Log to audit trail
	h.logAudit(ctx, &userID, "consent_given", "document_version", &versionID, nil, ipAddress, userAgent)

	c.JSON(http.StatusCreated, gin.H{
		"message":    "Consent saved successfully",
		"consent_id": consentID,
	})
}

// GetMyConsents returns all consents for the current user
func (h *Handler) GetMyConsents(c *gin.Context) {
	userID, err := middleware.GetUserID(c)
	if err != nil || userID == uuid.Nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
		return
	}

	ctx := context.Background()

	rows, err := h.db.Pool.Query(ctx, `
		SELECT uc.id, uc.consented, uc.consented_at, uc.withdrawn_at,
		       ld.id, ld.type, ld.name, ld.is_mandatory,
		       dv.id, dv.version, dv.language, dv.title
		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.user_id = $1
		ORDER BY uc.consented_at DESC
	`, userID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch consents"})
		return
	}
	defer rows.Close()

	var consents []map[string]interface{}
	for rows.Next() {
		var (
			consentID     uuid.UUID
			consented     bool
			consentedAt   time.Time
			withdrawnAt   *time.Time
			docID         uuid.UUID
			docType       string
			docName       string
			isMandatory   bool
			versionID     uuid.UUID
			version       string
			language      string
			title         string
		)

		if err := rows.Scan(&consentID, &consented, &consentedAt, &withdrawnAt,
			&docID, &docType, &docName, &isMandatory,
			&versionID, &version, &language, &title); err != nil {
			continue
		}

		consents = append(consents, map[string]interface{}{
			"consent_id":   consentID,
			"consented":    consented,
			"consented_at": consentedAt,
			"withdrawn_at": withdrawnAt,
			"document": map[string]interface{}{
				"id":           docID,
				"type":         docType,
				"name":         docName,
				"is_mandatory": isMandatory,
			},
			"version": map[string]interface{}{
				"id":       versionID,
				"version":  version,
				"language": language,
				"title":    title,
			},
		})
	}

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

// CheckConsent checks if the user has consented to a document
func (h *Handler) CheckConsent(c *gin.Context) {
	docType := c.Param("documentType")
	language := c.DefaultQuery("language", "de")

	userID, err := middleware.GetUserID(c)
	if err != nil || userID == uuid.Nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
		return
	}

	ctx := context.Background()

	// Get latest published version
	var latestVersionID uuid.UUID
	var latestVersion string
	err = h.db.Pool.QueryRow(ctx, `
		SELECT dv.id, dv.version
		FROM document_versions dv
		JOIN legal_documents ld ON dv.document_id = ld.id
		WHERE ld.type = $1 AND dv.language = $2 AND dv.status = 'published'
		ORDER BY dv.published_at DESC
		LIMIT 1
	`, docType, language).Scan(&latestVersionID, &latestVersion)

	if err != nil {
		c.JSON(http.StatusOK, models.ConsentCheckResponse{
			HasConsent:  false,
			NeedsUpdate: false,
		})
		return
	}

	// Check if user has consented to this version
	var consentedVersionID uuid.UUID
	var consentedVersion string
	var consentedAt time.Time
	err = h.db.Pool.QueryRow(ctx, `
		SELECT dv.id, dv.version, uc.consented_at
		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.user_id = $1 AND ld.type = $2 AND uc.consented = true AND uc.withdrawn_at IS NULL
		ORDER BY uc.consented_at DESC
		LIMIT 1
	`, userID, docType).Scan(&consentedVersionID, &consentedVersion, &consentedAt)

	if err != nil {
		// No consent found
		latestIDStr := latestVersionID.String()
		c.JSON(http.StatusOK, models.ConsentCheckResponse{
			HasConsent:       false,
			CurrentVersionID: &latestIDStr,
			NeedsUpdate:      true,
		})
		return
	}

	// Check if consent is for latest version
	needsUpdate := consentedVersionID != latestVersionID
	latestIDStr := latestVersionID.String()
	consentedVerStr := consentedVersion

	c.JSON(http.StatusOK, models.ConsentCheckResponse{
		HasConsent:       true,
		CurrentVersionID: &latestIDStr,
		ConsentedVersion: &consentedVerStr,
		NeedsUpdate:      needsUpdate,
		ConsentedAt:      &consentedAt,
	})
}

// WithdrawConsent withdraws a consent
func (h *Handler) WithdrawConsent(c *gin.Context) {
	consentID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid consent ID"})
		return
	}

	userID, err := middleware.GetUserID(c)
	if err != nil || userID == uuid.Nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
		return
	}

	ctx := context.Background()
	ipAddress := middleware.GetClientIP(c)
	userAgent := middleware.GetUserAgent(c)

	// Update consent
	result, err := h.db.Pool.Exec(ctx, `
		UPDATE user_consents
		SET withdrawn_at = NOW(), consented = false
		WHERE id = $1 AND user_id = $2
	`, consentID, userID)

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

	// Log to audit trail
	h.logAudit(ctx, &userID, "consent_withdrawn", "consent", &consentID, nil, ipAddress, userAgent)

	c.JSON(http.StatusOK, gin.H{"message": "Consent withdrawn successfully"})
}
