package handlers

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

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

// Handler holds all HTTP handlers
type Handler struct {
	db *database.DB
}

// New creates a new Handler instance
func New(db *database.DB) *Handler {
	return &Handler{db: db}
}

// ========================================
// PUBLIC ENDPOINTS - Documents
// ========================================

// GetDocuments returns all active legal documents
func (h *Handler) GetDocuments(c *gin.Context) {
	ctx := context.Background()

	rows, err := h.db.Pool.Query(ctx, `
		SELECT id, type, name, description, is_mandatory, is_active, sort_order, created_at, updated_at
		FROM legal_documents
		WHERE is_active = true
		ORDER BY sort_order ASC
	`)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch documents"})
		return
	}
	defer rows.Close()

	var documents []models.LegalDocument
	for rows.Next() {
		var doc models.LegalDocument
		if err := rows.Scan(&doc.ID, &doc.Type, &doc.Name, &doc.Description,
			&doc.IsMandatory, &doc.IsActive, &doc.SortOrder, &doc.CreatedAt, &doc.UpdatedAt); err != nil {
			continue
		}
		documents = append(documents, doc)
	}

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

// GetDocumentByType returns a document by its type
func (h *Handler) GetDocumentByType(c *gin.Context) {
	docType := c.Param("type")
	ctx := context.Background()

	var doc models.LegalDocument
	err := h.db.Pool.QueryRow(ctx, `
		SELECT id, type, name, description, is_mandatory, is_active, sort_order, created_at, updated_at
		FROM legal_documents
		WHERE type = $1 AND is_active = true
	`, docType).Scan(&doc.ID, &doc.Type, &doc.Name, &doc.Description,
		&doc.IsMandatory, &doc.IsActive, &doc.SortOrder, &doc.CreatedAt, &doc.UpdatedAt)

	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Document not found"})
		return
	}

	c.JSON(http.StatusOK, doc)
}

// GetLatestDocumentVersion returns the latest published version of a document
func (h *Handler) GetLatestDocumentVersion(c *gin.Context) {
	docType := c.Param("type")
	language := c.DefaultQuery("language", "de")
	ctx := context.Background()

	var version models.DocumentVersion
	err := h.db.Pool.QueryRow(ctx, `
		SELECT dv.id, dv.document_id, dv.version, dv.language, dv.title, dv.content,
		       dv.summary, dv.status, dv.published_at, dv.created_at, dv.updated_at
		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(&version.ID, &version.DocumentID, &version.Version, &version.Language,
		&version.Title, &version.Content, &version.Summary, &version.Status,
		&version.PublishedAt, &version.CreatedAt, &version.UpdatedAt)

	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "No published version found"})
		return
	}

	c.JSON(http.StatusOK, version)
}

// ========================================
// 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"})
}

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

// GetCookieCategories returns all active cookie categories
func (h *Handler) GetCookieCategories(c *gin.Context) {
	language := c.DefaultQuery("language", "de")
	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
		FROM cookie_categories
		WHERE is_active = true
		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 []map[string]interface{}
	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); err != nil {
			continue
		}

		// Return localized data
		displayName := cat.DisplayNameDE
		description := cat.DescriptionDE
		if language == "en" && cat.DisplayNameEN != nil {
			displayName = *cat.DisplayNameEN
			if cat.DescriptionEN != nil {
				description = cat.DescriptionEN
			}
		}

		categories = append(categories, map[string]interface{}{
			"id":           cat.ID,
			"name":         cat.Name,
			"display_name": displayName,
			"description":  description,
			"is_mandatory": cat.IsMandatory,
		})
	}

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

// SetCookieConsent sets cookie preferences for a user
func (h *Handler) SetCookieConsent(c *gin.Context) {
	var req models.CookieConsentRequest
	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
	}

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

	// Process each category
	for _, cat := range req.Categories {
		categoryID, err := uuid.Parse(cat.CategoryID)
		if err != nil {
			continue
		}

		_, err = h.db.Pool.Exec(ctx, `
			INSERT INTO cookie_consents (user_id, category_id, consented)
			VALUES ($1, $2, $3)
			ON CONFLICT (user_id, category_id)
			DO UPDATE SET consented = $3, updated_at = NOW()
		`, userID, categoryID, cat.Consented)

		if err != nil {
			continue
		}
	}

	// Log to audit trail
	h.logAudit(ctx, &userID, "cookie_consent_updated", "cookie", nil, nil, ipAddress, userAgent)

	c.JSON(http.StatusOK, gin.H{"message": "Cookie preferences saved"})
}

// GetMyCookieConsent returns cookie preferences for the current user
func (h *Handler) GetMyCookieConsent(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 cc.category_id, cc.consented, cc.updated_at,
		       cat.name, cat.display_name_de, cat.is_mandatory
		FROM cookie_consents cc
		JOIN cookie_categories cat ON cc.category_id = cat.id
		WHERE cc.user_id = $1
	`, userID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch preferences"})
		return
	}
	defer rows.Close()

	var consents []map[string]interface{}
	for rows.Next() {
		var (
			categoryID   uuid.UUID
			consented    bool
			updatedAt    time.Time
			name         string
			displayName  string
			isMandatory  bool
		)

		if err := rows.Scan(&categoryID, &consented, &updatedAt, &name, &displayName, &isMandatory); err != nil {
			continue
		}

		consents = append(consents, map[string]interface{}{
			"category_id":  categoryID,
			"name":         name,
			"display_name": displayName,
			"consented":    consented,
			"is_mandatory": isMandatory,
			"updated_at":   updatedAt,
		})
	}

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

// ========================================
// GDPR / DATA SUBJECT RIGHTS
// ========================================

// GetMyData returns all data we have about the user
func (h *Handler) GetMyData(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()
	ipAddress := middleware.GetClientIP(c)
	userAgent := middleware.GetUserAgent(c)

	// Get user info
	var user models.User
	err = h.db.Pool.QueryRow(ctx, `
		SELECT id, external_id, email, role, created_at, updated_at
		FROM users WHERE id = $1
	`, userID).Scan(&user.ID, &user.ExternalID, &user.Email, &user.Role, &user.CreatedAt, &user.UpdatedAt)

	// Get consents
	consentRows, _ := h.db.Pool.Query(ctx, `
		SELECT uc.consented, uc.consented_at, ld.type, ld.name, dv.version
		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
	`, userID)
	defer consentRows.Close()

	var consents []map[string]interface{}
	for consentRows.Next() {
		var consented bool
		var consentedAt time.Time
		var docType, docName, version string
		consentRows.Scan(&consented, &consentedAt, &docType, &docName, &version)
		consents = append(consents, map[string]interface{}{
			"document_type": docType,
			"document_name": docName,
			"version":       version,
			"consented":     consented,
			"consented_at":  consentedAt,
		})
	}

	// Get cookie consents
	cookieRows, _ := h.db.Pool.Query(ctx, `
		SELECT cat.name, cc.consented, cc.updated_at
		FROM cookie_consents cc
		JOIN cookie_categories cat ON cc.category_id = cat.id
		WHERE cc.user_id = $1
	`, userID)
	defer cookieRows.Close()

	var cookieConsents []map[string]interface{}
	for cookieRows.Next() {
		var name string
		var consented bool
		var updatedAt time.Time
		cookieRows.Scan(&name, &consented, &updatedAt)
		cookieConsents = append(cookieConsents, map[string]interface{}{
			"category":   name,
			"consented":  consented,
			"updated_at": updatedAt,
		})
	}

	// Log data access
	h.logAudit(ctx, &userID, "data_access", "user", &userID, nil, ipAddress, userAgent)

	c.JSON(http.StatusOK, gin.H{
		"user": map[string]interface{}{
			"id":         user.ID,
			"email":      user.Email,
			"created_at": user.CreatedAt,
		},
		"consents":        consents,
		"cookie_consents": cookieConsents,
		"exported_at":     time.Now(),
	})
}

// RequestDataExport creates a data export request
func (h *Handler) RequestDataExport(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()
	ipAddress := middleware.GetClientIP(c)
	userAgent := middleware.GetUserAgent(c)

	var requestID uuid.UUID
	err = h.db.Pool.QueryRow(ctx, `
		INSERT INTO data_export_requests (user_id, status)
		VALUES ($1, 'pending')
		RETURNING id
	`, userID).Scan(&requestID)

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

	// Log to audit trail
	h.logAudit(ctx, &userID, "data_export_requested", "export_request", &requestID, nil, ipAddress, userAgent)

	c.JSON(http.StatusAccepted, gin.H{
		"message":    "Export request created. You will be notified when ready.",
		"request_id": requestID,
	})
}

// RequestDataDeletion creates a data deletion request
func (h *Handler) RequestDataDeletion(c *gin.Context) {
	userID, err := middleware.GetUserID(c)
	if err != nil || userID == uuid.Nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
		return
	}

	var req struct {
		Reason string `json:"reason"`
	}
	c.ShouldBindJSON(&req)

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

	var requestID uuid.UUID
	err = h.db.Pool.QueryRow(ctx, `
		INSERT INTO data_deletion_requests (user_id, status, reason)
		VALUES ($1, 'pending', $2)
		RETURNING id
	`, userID, req.Reason).Scan(&requestID)

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

	// Log to audit trail
	h.logAudit(ctx, &userID, "data_deletion_requested", "deletion_request", &requestID, nil, ipAddress, userAgent)

	c.JSON(http.StatusAccepted, gin.H{
		"message":    "Deletion request created. We will process your request within 30 days.",
		"request_id": requestID,
	})
}

// ========================================
// ADMIN ENDPOINTS - Document Management
// ========================================

// AdminGetDocuments returns all documents (including inactive) for admin
func (h *Handler) AdminGetDocuments(c *gin.Context) {
	ctx := context.Background()

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

	var documents []models.LegalDocument
	for rows.Next() {
		var doc models.LegalDocument
		if err := rows.Scan(&doc.ID, &doc.Type, &doc.Name, &doc.Description,
			&doc.IsMandatory, &doc.IsActive, &doc.SortOrder, &doc.CreatedAt, &doc.UpdatedAt); err != nil {
			continue
		}
		documents = append(documents, doc)
	}

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

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

	ctx := context.Background()

	var docID uuid.UUID
	err := h.db.Pool.QueryRow(ctx, `
		INSERT INTO legal_documents (type, name, description, is_mandatory)
		VALUES ($1, $2, $3, $4)
		RETURNING id
	`, req.Type, req.Name, req.Description, req.IsMandatory).Scan(&docID)

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

	c.JSON(http.StatusCreated, gin.H{
		"message": "Document created successfully",
		"id":      docID,
	})
}

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

	var req struct {
		Name        *string `json:"name"`
		Description *string `json:"description"`
		IsMandatory *bool   `json:"is_mandatory"`
		IsActive    *bool   `json:"is_active"`
		SortOrder   *int    `json:"sort_order"`
	}
	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 legal_documents
		SET name = COALESCE($2, name),
		    description = COALESCE($3, description),
		    is_mandatory = COALESCE($4, is_mandatory),
		    is_active = COALESCE($5, is_active),
		    sort_order = COALESCE($6, sort_order),
		    updated_at = NOW()
		WHERE id = $1
	`, docID, req.Name, req.Description, req.IsMandatory, req.IsActive, req.SortOrder)

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

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

// AdminDeleteDocument soft-deletes a document (sets is_active to false)
func (h *Handler) AdminDeleteDocument(c *gin.Context) {
	docID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid document ID"})
		return
	}

	ctx := context.Background()

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

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

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

// ========================================
// ADMIN ENDPOINTS - Version Management
// ========================================

// AdminGetVersions returns all versions for a document
func (h *Handler) AdminGetVersions(c *gin.Context) {
	docID, err := uuid.Parse(c.Param("docId"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid document ID"})
		return
	}

	ctx := context.Background()

	rows, err := h.db.Pool.Query(ctx, `
		SELECT id, document_id, version, language, title, content, summary, status,
		       published_at, scheduled_publish_at, created_by, approved_by, approved_at, created_at, updated_at
		FROM document_versions
		WHERE document_id = $1
		ORDER BY created_at DESC
	`, docID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch versions"})
		return
	}
	defer rows.Close()

	var versions []models.DocumentVersion
	for rows.Next() {
		var v models.DocumentVersion
		if err := rows.Scan(&v.ID, &v.DocumentID, &v.Version, &v.Language, &v.Title, &v.Content,
			&v.Summary, &v.Status, &v.PublishedAt, &v.ScheduledPublishAt, &v.CreatedBy, &v.ApprovedBy, &v.ApprovedAt, &v.CreatedAt, &v.UpdatedAt); err != nil {
			continue
		}
		versions = append(versions, v)
	}

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

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

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

	userID, _ := middleware.GetUserID(c)
	ctx := context.Background()

	var versionID uuid.UUID
	err = h.db.Pool.QueryRow(ctx, `
		INSERT INTO document_versions (document_id, version, language, title, content, summary, status, created_by)
		VALUES ($1, $2, $3, $4, $5, $6, 'draft', $7)
		RETURNING id
	`, docID, req.Version, req.Language, req.Title, req.Content, req.Summary, userID).Scan(&versionID)

	if err != nil {
		// Check for unique constraint violation
		errStr := err.Error()
		if strings.Contains(errStr, "duplicate key") || strings.Contains(errStr, "unique constraint") {
			c.JSON(http.StatusConflict, gin.H{"error": "Eine Version mit dieser Versionsnummer und Sprache existiert bereits für dieses Dokument"})
			return
		}
		// Log the actual error for debugging
		fmt.Printf("POST /api/v1/admin/versions ✗ %v\n", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create version: " + errStr})
		return
	}

	c.JSON(http.StatusCreated, gin.H{
		"message": "Version created successfully",
		"id":      versionID,
	})
}

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

	var req models.UpdateVersionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
		return
	}

	ctx := context.Background()

	// Check if version is in draft or review status (only these can be edited)
	var status string
	err = h.db.Pool.QueryRow(ctx, `SELECT status FROM document_versions WHERE id = $1`, versionID).Scan(&status)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Version not found"})
		return
	}

	if status != "draft" && status != "review" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Only draft or review versions can be edited"})
		return
	}

	result, err := h.db.Pool.Exec(ctx, `
		UPDATE document_versions
		SET title = COALESCE($2, title),
		    content = COALESCE($3, content),
		    summary = COALESCE($4, summary),
		    status = COALESCE($5, status),
		    updated_at = NOW()
		WHERE id = $1
	`, versionID, req.Title, req.Content, req.Summary, req.Status)

	if err != nil || result.RowsAffected() == 0 {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update version"})
		return
	}

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

// AdminPublishVersion publishes a document version
func (h *Handler) AdminPublishVersion(c *gin.Context) {
	versionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid version ID"})
		return
	}

	userID, _ := middleware.GetUserID(c)
	ctx := context.Background()

	// Check current status
	var status string
	err = h.db.Pool.QueryRow(ctx, `SELECT status FROM document_versions WHERE id = $1`, versionID).Scan(&status)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Version not found"})
		return
	}

	if status != "approved" && status != "review" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Only approved or review versions can be published"})
		return
	}

	result, err := h.db.Pool.Exec(ctx, `
		UPDATE document_versions
		SET status = 'published',
		    published_at = NOW(),
		    approved_by = $2,
		    updated_at = NOW()
		WHERE id = $1
	`, versionID, userID)

	if err != nil || result.RowsAffected() == 0 {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to publish version"})
		return
	}

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

// AdminArchiveVersion archives a document version
func (h *Handler) AdminArchiveVersion(c *gin.Context) {
	versionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid version ID"})
		return
	}

	ctx := context.Background()

	result, err := h.db.Pool.Exec(ctx, `
		UPDATE document_versions
		SET status = 'archived', updated_at = NOW()
		WHERE id = $1
	`, versionID)

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

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

// AdminDeleteVersion permanently deletes a draft/rejected version
// Only draft and rejected versions can be deleted. Published versions must be archived.
func (h *Handler) AdminDeleteVersion(c *gin.Context) {
	versionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid version ID"})
		return
	}

	ctx := context.Background()

	// First check the version status - only draft/rejected can be deleted
	var status string
	var version string
	var docID uuid.UUID
	err = h.db.Pool.QueryRow(ctx, `
		SELECT status, version, document_id FROM document_versions WHERE id = $1
	`, versionID).Scan(&status, &version, &docID)

	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Version not found"})
		return
	}

	// Only allow deletion of draft and rejected versions
	if status != "draft" && status != "rejected" {
		c.JSON(http.StatusForbidden, gin.H{
			"error":   "Cannot delete version",
			"message": "Only draft or rejected versions can be deleted. Published versions must be archived instead.",
			"status":  status,
		})
		return
	}

	// Delete the version
	result, err := h.db.Pool.Exec(ctx, `
		DELETE FROM document_versions WHERE id = $1
	`, versionID)

	if err != nil || result.RowsAffected() == 0 {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete version"})
		return
	}

	// Log the deletion
	userID, _ := c.Get("user_id")
	h.db.Pool.Exec(ctx, `
		INSERT INTO consent_audit_log (action, entity_type, entity_id, user_id, details, ip_address, user_agent)
		VALUES ('version_deleted', 'document_version', $1, $2, $3, $4, $5)
	`, versionID, userID, "Version "+version+" permanently deleted", c.ClientIP(), c.Request.UserAgent())

	c.JSON(http.StatusOK, gin.H{
		"message":          "Version deleted successfully",
		"deleted_version":  version,
		"version_id":       versionID,
	})
}

// ========================================
// 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})
}

// ========================================
// ADMIN ENDPOINTS - Version Approval Workflow (DSB)
// ========================================

// AdminSubmitForReview submits a version for DSB review
func (h *Handler) AdminSubmitForReview(c *gin.Context) {
	versionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid version ID"})
		return
	}

	userID, _ := middleware.GetUserID(c)
	ctx := context.Background()
	ipAddress := middleware.GetClientIP(c)
	userAgent := middleware.GetUserAgent(c)

	// Check current status
	var status string
	err = h.db.Pool.QueryRow(ctx, `SELECT status FROM document_versions WHERE id = $1`, versionID).Scan(&status)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Version not found"})
		return
	}

	if status != "draft" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Only draft versions can be submitted for review"})
		return
	}

	// Update status to review
	_, err = h.db.Pool.Exec(ctx, `
		UPDATE document_versions
		SET status = 'review', updated_at = NOW()
		WHERE id = $1
	`, versionID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to submit for review"})
		return
	}

	// Log approval action
	_, err = h.db.Pool.Exec(ctx, `
		INSERT INTO version_approvals (version_id, approver_id, action, comment)
		VALUES ($1, $2, 'submitted', 'Submitted for DSB review')
	`, versionID, userID)

	h.logAudit(ctx, &userID, "version_submitted_review", "document_version", &versionID, nil, ipAddress, userAgent)

	c.JSON(http.StatusOK, gin.H{"message": "Version submitted for review"})
}

// AdminApproveVersion approves a version with scheduled publish date (DSB only)
func (h *Handler) AdminApproveVersion(c *gin.Context) {
	versionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid version ID"})
		return
	}

	// Check if user is DSB or Admin (for dev purposes)
	if !middleware.IsDSB(c) && !middleware.IsAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "Only Data Protection Officers can approve versions"})
		return
	}

	var req struct {
		Comment            string  `json:"comment"`
		ScheduledPublishAt *string `json:"scheduled_publish_at"` // ISO 8601: "2026-01-01T00:00:00Z"
	}
	c.ShouldBindJSON(&req)

	// Validate scheduled publish date
	var scheduledAt *time.Time
	if req.ScheduledPublishAt != nil && *req.ScheduledPublishAt != "" {
		parsed, err := time.Parse(time.RFC3339, *req.ScheduledPublishAt)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid scheduled_publish_at format. Use ISO 8601 (e.g., 2026-01-01T00:00:00Z)"})
			return
		}
		if parsed.Before(time.Now()) {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Scheduled publish date must be in the future"})
			return
		}
		scheduledAt = &parsed
	}

	userID, _ := middleware.GetUserID(c)
	ctx := context.Background()
	ipAddress := middleware.GetClientIP(c)
	userAgent := middleware.GetUserAgent(c)

	// Check current status
	var status string
	var createdBy *uuid.UUID
	err = h.db.Pool.QueryRow(ctx, `SELECT status, created_by FROM document_versions WHERE id = $1`, versionID).Scan(&status, &createdBy)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Version not found"})
		return
	}

	if status != "review" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Only versions in review status can be approved"})
		return
	}

	// Four-eyes principle: DSB cannot approve their own version
	// Exception: Admins can approve their own versions for development/testing purposes
	role, _ := c.Get("role")
	roleStr, _ := role.(string)
	if createdBy != nil && *createdBy == userID && roleStr != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "You cannot approve your own version (four-eyes principle)"})
		return
	}

	// Determine new status: 'scheduled' if date set, otherwise 'approved'
	newStatus := "approved"
	if scheduledAt != nil {
		newStatus = "scheduled"
	}

	// Update status to approved/scheduled
	_, err = h.db.Pool.Exec(ctx, `
		UPDATE document_versions
		SET status = $2, approved_by = $3, approved_at = NOW(), scheduled_publish_at = $4, updated_at = NOW()
		WHERE id = $1
	`, versionID, newStatus, userID, scheduledAt)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to approve version"})
		return
	}

	// Log approval action
	comment := req.Comment
	if comment == "" {
		if scheduledAt != nil {
			comment = "Approved by DSB, scheduled for " + scheduledAt.Format("02.01.2006 15:04")
		} else {
			comment = "Approved by DSB"
		}
	}
	_, err = h.db.Pool.Exec(ctx, `
		INSERT INTO version_approvals (version_id, approver_id, action, comment)
		VALUES ($1, $2, 'approved', $3)
	`, versionID, userID, comment)

	h.logAudit(ctx, &userID, "version_approved", "document_version", &versionID, &comment, ipAddress, userAgent)

	response := gin.H{"message": "Version approved", "status": newStatus}
	if scheduledAt != nil {
		response["scheduled_publish_at"] = scheduledAt.Format(time.RFC3339)
	}
	c.JSON(http.StatusOK, response)
}

// AdminRejectVersion rejects a version (DSB only)
func (h *Handler) AdminRejectVersion(c *gin.Context) {
	versionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid version ID"})
		return
	}

	// Check if user is DSB
	if !middleware.IsDSB(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "Only Data Protection Officers can reject versions"})
		return
	}

	var req struct {
		Comment string `json:"comment" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Comment is required when rejecting"})
		return
	}

	userID, _ := middleware.GetUserID(c)
	ctx := context.Background()
	ipAddress := middleware.GetClientIP(c)
	userAgent := middleware.GetUserAgent(c)

	// Check current status
	var status string
	err = h.db.Pool.QueryRow(ctx, `SELECT status FROM document_versions WHERE id = $1`, versionID).Scan(&status)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Version not found"})
		return
	}

	if status != "review" && status != "approved" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Only versions in review or approved status can be rejected"})
		return
	}

	// Update status back to draft
	_, err = h.db.Pool.Exec(ctx, `
		UPDATE document_versions
		SET status = 'draft', approved_by = NULL, updated_at = NOW()
		WHERE id = $1
	`, versionID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to reject version"})
		return
	}

	// Log rejection
	_, err = h.db.Pool.Exec(ctx, `
		INSERT INTO version_approvals (version_id, approver_id, action, comment)
		VALUES ($1, $2, 'rejected', $3)
	`, versionID, userID, req.Comment)

	h.logAudit(ctx, &userID, "version_rejected", "document_version", &versionID, &req.Comment, ipAddress, userAgent)

	c.JSON(http.StatusOK, gin.H{"message": "Version rejected and returned to draft"})
}

// AdminCompareVersions returns two versions for side-by-side comparison
func (h *Handler) AdminCompareVersions(c *gin.Context) {
	versionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid version ID"})
		return
	}

	ctx := context.Background()

	// Get the current version and its document
	var currentVersion models.DocumentVersion
	var documentID uuid.UUID
	err = h.db.Pool.QueryRow(ctx, `
		SELECT id, document_id, version, language, title, content, summary, status, created_at, updated_at
		FROM document_versions
		WHERE id = $1
	`, versionID).Scan(&currentVersion.ID, &documentID, &currentVersion.Version, &currentVersion.Language,
		&currentVersion.Title, &currentVersion.Content, &currentVersion.Summary, &currentVersion.Status,
		&currentVersion.CreatedAt, &currentVersion.UpdatedAt)

	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Version not found"})
		return
	}

	// Get the currently published version (if any)
	var publishedVersion *models.DocumentVersion
	var pv models.DocumentVersion
	err = h.db.Pool.QueryRow(ctx, `
		SELECT id, document_id, version, language, title, content, summary, status, published_at, created_at, updated_at
		FROM document_versions
		WHERE document_id = $1 AND language = $2 AND status = 'published'
		ORDER BY published_at DESC
		LIMIT 1
	`, documentID, currentVersion.Language).Scan(&pv.ID, &pv.DocumentID, &pv.Version, &pv.Language,
		&pv.Title, &pv.Content, &pv.Summary, &pv.Status, &pv.PublishedAt, &pv.CreatedAt, &pv.UpdatedAt)

	if err == nil && pv.ID != currentVersion.ID {
		publishedVersion = &pv
	}

	// Get approval history
	rows, err := h.db.Pool.Query(ctx, `
		SELECT va.action, va.comment, va.created_at, u.email
		FROM version_approvals va
		LEFT JOIN users u ON va.approver_id = u.id
		WHERE va.version_id = $1
		ORDER BY va.created_at DESC
	`, versionID)

	var approvalHistory []map[string]interface{}
	if err == nil {
		defer rows.Close()
		for rows.Next() {
			var action, email string
			var comment *string
			var createdAt time.Time
			if err := rows.Scan(&action, &comment, &createdAt, &email); err == nil {
				approvalHistory = append(approvalHistory, map[string]interface{}{
					"action":     action,
					"comment":    comment,
					"created_at": createdAt,
					"approver":   email,
				})
			}
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"current_version":   currentVersion,
		"published_version": publishedVersion,
		"approval_history":  approvalHistory,
	})
}

// AdminGetApprovalHistory returns the approval history for a version
func (h *Handler) AdminGetApprovalHistory(c *gin.Context) {
	versionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid version ID"})
		return
	}

	ctx := context.Background()

	rows, err := h.db.Pool.Query(ctx, `
		SELECT va.id, va.action, va.comment, va.created_at, u.email, u.name
		FROM version_approvals va
		LEFT JOIN users u ON va.approver_id = u.id
		WHERE va.version_id = $1
		ORDER BY va.created_at DESC
	`, versionID)

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch approval history"})
		return
	}
	defer rows.Close()

	var history []map[string]interface{}
	for rows.Next() {
		var id uuid.UUID
		var action string
		var comment *string
		var createdAt time.Time
		var email, name *string

		if err := rows.Scan(&id, &action, &comment, &createdAt, &email, &name); err != nil {
			continue
		}

		history = append(history, map[string]interface{}{
			"id":         id,
			"action":     action,
			"comment":    comment,
			"created_at": createdAt,
			"approver":   email,
			"name":       name,
		})
	}

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

// ========================================
// HELPER FUNCTIONS
// ========================================

func (h *Handler) logAudit(ctx context.Context, userID *uuid.UUID, action, entityType string, entityID *uuid.UUID, details *string, ipAddress, userAgent string) {
	h.db.Pool.Exec(ctx, `
		INSERT INTO consent_audit_log (user_id, action, entity_type, entity_id, details, ip_address, user_agent)
		VALUES ($1, $2, $3, $4, $5, $6, $7)
	`, userID, action, entityType, entityID, details, ipAddress, userAgent)
}

func parseIntFromQuery(s string) (int, error) {
	return strconv.Atoi(s)
}

// ========================================
// SCHEDULED PUBLISHING
// ========================================

// ProcessScheduledPublishing publishes all versions that are due
// This should be called by a cron job or scheduler
func (h *Handler) ProcessScheduledPublishing(c *gin.Context) {
	ctx := context.Background()

	// Find all scheduled versions that are due
	rows, err := h.db.Pool.Query(ctx, `
		SELECT id, document_id, version
		FROM document_versions
		WHERE status = 'scheduled'
		  AND scheduled_publish_at IS NOT NULL
		  AND scheduled_publish_at <= NOW()
	`)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch scheduled versions"})
		return
	}
	defer rows.Close()

	var published []string
	for rows.Next() {
		var versionID, docID uuid.UUID
		var version string
		if err := rows.Scan(&versionID, &docID, &version); err != nil {
			continue
		}

		// Publish this version
		_, err := h.db.Pool.Exec(ctx, `
			UPDATE document_versions
			SET status = 'published', published_at = NOW(), updated_at = NOW()
			WHERE id = $1
		`, versionID)

		if err == nil {
			// Archive previous published versions for this document
			h.db.Pool.Exec(ctx, `
				UPDATE document_versions
				SET status = 'archived', updated_at = NOW()
				WHERE document_id = $1 AND id != $2 AND status = 'published'
			`, docID, versionID)

			// Log the publishing
			details := fmt.Sprintf("Version %s automatically published by scheduler", version)
			h.logAudit(ctx, nil, "version_scheduled_published", "document_version", &versionID, &details, "", "scheduler")

			published = append(published, version)
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"message":           "Scheduled publishing processed",
		"published_count":   len(published),
		"published_versions": published,
	})
}

// GetScheduledVersions returns all versions scheduled for publishing
func (h *Handler) GetScheduledVersions(c *gin.Context) {
	ctx := context.Background()

	rows, err := h.db.Pool.Query(ctx, `
		SELECT dv.id, dv.document_id, dv.version, dv.title, dv.scheduled_publish_at, ld.name as document_name
		FROM document_versions dv
		JOIN legal_documents ld ON ld.id = dv.document_id
		WHERE dv.status = 'scheduled'
		  AND dv.scheduled_publish_at IS NOT NULL
		ORDER BY dv.scheduled_publish_at ASC
	`)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch scheduled versions"})
		return
	}
	defer rows.Close()

	type ScheduledVersion struct {
		ID                 uuid.UUID  `json:"id"`
		DocumentID         uuid.UUID  `json:"document_id"`
		Version            string     `json:"version"`
		Title              string     `json:"title"`
		ScheduledPublishAt *time.Time `json:"scheduled_publish_at"`
		DocumentName       string     `json:"document_name"`
	}

	var versions []ScheduledVersion
	for rows.Next() {
		var v ScheduledVersion
		if err := rows.Scan(&v.ID, &v.DocumentID, &v.Version, &v.Title, &v.ScheduledPublishAt, &v.DocumentName); err != nil {
			continue
		}
		versions = append(versions, v)
	}

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