package handlers

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

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// ========================================
// Cookie Banner SDK API Handlers
// ========================================
// Diese Endpoints werden vom @breakpilot/consent-sdk verwendet
// für anonyme (device-basierte) Cookie-Einwilligungen.

// BannerConsentRecord repräsentiert einen anonymen Consent-Eintrag
type BannerConsentRecord struct {
	ID                string                 `json:"id"`
	SiteID            string                 `json:"site_id"`
	DeviceFingerprint string                 `json:"device_fingerprint"`
	UserID            *string                `json:"user_id,omitempty"`
	Categories        map[string]bool        `json:"categories"`
	Vendors           map[string]bool        `json:"vendors,omitempty"`
	TCFString         *string                `json:"tcf_string,omitempty"`
	IPHash            *string                `json:"ip_hash,omitempty"`
	UserAgent         *string                `json:"user_agent,omitempty"`
	Language          *string                `json:"language,omitempty"`
	Platform          *string                `json:"platform,omitempty"`
	AppVersion        *string                `json:"app_version,omitempty"`
	Version           string                 `json:"version"`
	CreatedAt         time.Time              `json:"created_at"`
	UpdatedAt         time.Time              `json:"updated_at"`
	ExpiresAt         *time.Time             `json:"expires_at,omitempty"`
	RevokedAt         *time.Time             `json:"revoked_at,omitempty"`
}

// BannerConsentRequest ist der Request-Body für POST /consent
type BannerConsentRequest struct {
	SiteID            string          `json:"siteId" binding:"required"`
	UserID            *string         `json:"userId,omitempty"`
	DeviceFingerprint string          `json:"deviceFingerprint" binding:"required"`
	Consent           ConsentData     `json:"consent" binding:"required"`
	Metadata          *ConsentMetadata `json:"metadata,omitempty"`
}

// ConsentData enthält die eigentlichen Consent-Daten
type ConsentData struct {
	Categories map[string]bool `json:"categories" binding:"required"`
	Vendors    map[string]bool `json:"vendors,omitempty"`
}

// ConsentMetadata enthält optionale Metadaten
type ConsentMetadata struct {
	UserAgent        *string `json:"userAgent,omitempty"`
	Language         *string `json:"language,omitempty"`
	ScreenResolution *string `json:"screenResolution,omitempty"`
	Platform         *string `json:"platform,omitempty"`
	AppVersion       *string `json:"appVersion,omitempty"`
}

// BannerConsentResponse ist die Antwort auf POST /consent
type BannerConsentResponse struct {
	ConsentID string    `json:"consentId"`
	Timestamp string    `json:"timestamp"`
	ExpiresAt string    `json:"expiresAt"`
	Version   string    `json:"version"`
}

// SiteConfig repräsentiert die Konfiguration für eine Site
type SiteConfig struct {
	SiteID     string           `json:"siteId"`
	SiteName   string           `json:"siteName"`
	Categories []CategoryConfig `json:"categories"`
	UI         UIConfig         `json:"ui"`
	Legal      LegalConfig      `json:"legal"`
	TCF        *TCFConfig       `json:"tcf,omitempty"`
}

// CategoryConfig repräsentiert eine Consent-Kategorie
type CategoryConfig struct {
	ID          string            `json:"id"`
	Name        map[string]string `json:"name"`
	Description map[string]string `json:"description"`
	Required    bool              `json:"required"`
	Vendors     []VendorConfig    `json:"vendors"`
}

// VendorConfig repräsentiert einen Vendor (Third-Party)
type VendorConfig struct {
	ID               string       `json:"id"`
	Name             string       `json:"name"`
	PrivacyPolicyURL string       `json:"privacyPolicyUrl"`
	Cookies          []CookieInfo `json:"cookies"`
}

// CookieInfo repräsentiert ein Cookie
type CookieInfo struct {
	Name        string `json:"name"`
	Expiration  string `json:"expiration"`
	Description string `json:"description"`
}

// UIConfig repräsentiert UI-Einstellungen
type UIConfig struct {
	Theme    string `json:"theme"`
	Position string `json:"position"`
}

// LegalConfig repräsentiert rechtliche Informationen
type LegalConfig struct {
	PrivacyPolicyURL string `json:"privacyPolicyUrl"`
	ImprintURL       string `json:"imprintUrl"`
}

// TCFConfig repräsentiert TCF 2.2 Einstellungen
type TCFConfig struct {
	Enabled    bool `json:"enabled"`
	CmpID      int  `json:"cmpId"`
	CmpVersion int  `json:"cmpVersion"`
}

// ========================================
// Handler Methods
// ========================================

// CreateBannerConsent erstellt oder aktualisiert einen Consent-Eintrag
// POST /api/v1/banner/consent
func (h *Handler) CreateBannerConsent(c *gin.Context) {
	var req BannerConsentRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   "invalid_request",
			"message": "Invalid request body: " + err.Error(),
		})
		return
	}

	ctx := context.Background()

	// IP-Adresse anonymisieren
	ipHash := anonymizeIP(c.ClientIP())

	// Consent-ID generieren
	consentID := uuid.New().String()

	// Ablaufdatum (1 Jahr)
	expiresAt := time.Now().AddDate(1, 0, 0)

	// Categories und Vendors als JSON
	categoriesJSON, _ := json.Marshal(req.Consent.Categories)
	vendorsJSON, _ := json.Marshal(req.Consent.Vendors)

	// Metadaten extrahieren
	var userAgent, language, platform, appVersion *string
	if req.Metadata != nil {
		userAgent = req.Metadata.UserAgent
		language = req.Metadata.Language
		platform = req.Metadata.Platform
		appVersion = req.Metadata.AppVersion
	}

	// In Datenbank speichern
	_, err := h.db.Pool.Exec(ctx, `
		INSERT INTO banner_consents (
			id, site_id, device_fingerprint, user_id,
			categories, vendors, ip_hash, user_agent,
			language, platform, app_version, version,
			expires_at, created_at, updated_at
		) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, NOW(), NOW())
		ON CONFLICT (site_id, device_fingerprint)
		DO UPDATE SET
			categories = $5,
			vendors = $6,
			ip_hash = $7,
			user_agent = $8,
			language = $9,
			platform = $10,
			app_version = $11,
			version = $12,
			expires_at = $13,
			updated_at = NOW()
		RETURNING id
	`, consentID, req.SiteID, req.DeviceFingerprint, req.UserID,
		categoriesJSON, vendorsJSON, ipHash, userAgent,
		language, platform, appVersion, "1.0.0", expiresAt)

	if err != nil {
		// Fallback: Existierenden Consent abrufen
		var existingID string
		err2 := h.db.Pool.QueryRow(ctx, `
			SELECT id FROM banner_consents
			WHERE site_id = $1 AND device_fingerprint = $2
		`, req.SiteID, req.DeviceFingerprint).Scan(&existingID)

		if err2 == nil {
			consentID = existingID
		}
	}

	// Audit-Log schreiben
	h.logBannerConsentAudit(ctx, consentID, "created", req, ipHash)

	// Response
	c.JSON(http.StatusCreated, BannerConsentResponse{
		ConsentID: consentID,
		Timestamp: time.Now().UTC().Format(time.RFC3339),
		ExpiresAt: expiresAt.UTC().Format(time.RFC3339),
		Version:   "1.0.0",
	})
}

// GetBannerConsent ruft einen bestehenden Consent ab
// GET /api/v1/banner/consent?siteId=xxx&deviceFingerprint=xxx
func (h *Handler) GetBannerConsent(c *gin.Context) {
	siteID := c.Query("siteId")
	deviceFingerprint := c.Query("deviceFingerprint")

	if siteID == "" || deviceFingerprint == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":   "missing_parameters",
			"message": "siteId and deviceFingerprint are required",
		})
		return
	}

	ctx := context.Background()

	var record BannerConsentRecord
	var categoriesJSON, vendorsJSON []byte

	err := h.db.Pool.QueryRow(ctx, `
		SELECT id, site_id, device_fingerprint, user_id,
			   categories, vendors, version,
			   created_at, updated_at, expires_at, revoked_at
		FROM banner_consents
		WHERE site_id = $1 AND device_fingerprint = $2 AND revoked_at IS NULL
	`, siteID, deviceFingerprint).Scan(
		&record.ID, &record.SiteID, &record.DeviceFingerprint, &record.UserID,
		&categoriesJSON, &vendorsJSON, &record.Version,
		&record.CreatedAt, &record.UpdatedAt, &record.ExpiresAt, &record.RevokedAt,
	)

	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{
			"error":   "consent_not_found",
			"message": "No consent record found",
		})
		return
	}

	// JSON parsen
	json.Unmarshal(categoriesJSON, &record.Categories)
	json.Unmarshal(vendorsJSON, &record.Vendors)

	c.JSON(http.StatusOK, gin.H{
		"consentId": record.ID,
		"consent": gin.H{
			"categories": record.Categories,
			"vendors":    record.Vendors,
		},
		"createdAt": record.CreatedAt.UTC().Format(time.RFC3339),
		"updatedAt": record.UpdatedAt.UTC().Format(time.RFC3339),
		"expiresAt": record.ExpiresAt.UTC().Format(time.RFC3339),
		"version":   record.Version,
	})
}

// RevokeBannerConsent widerruft einen Consent
// DELETE /api/v1/banner/consent/:consentId
func (h *Handler) RevokeBannerConsent(c *gin.Context) {
	consentID := c.Param("consentId")

	ctx := context.Background()

	result, err := h.db.Pool.Exec(ctx, `
		UPDATE banner_consents
		SET revoked_at = NOW(), updated_at = NOW()
		WHERE id = $1 AND revoked_at IS NULL
	`, consentID)

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

	if result.RowsAffected() == 0 {
		c.JSON(http.StatusNotFound, gin.H{
			"error":   "consent_not_found",
			"message": "Consent not found or already revoked",
		})
		return
	}

	// Audit-Log
	h.logBannerConsentAudit(ctx, consentID, "revoked", nil, anonymizeIP(c.ClientIP()))

	c.JSON(http.StatusOK, gin.H{
		"status":    "revoked",
		"revokedAt": time.Now().UTC().Format(time.RFC3339),
	})
}
