package handlers

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

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

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