package handlers

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

	"github.com/breakpilot/ai-compliance-sdk/internal/audit"
	"github.com/breakpilot/ai-compliance-sdk/internal/llm"
	"github.com/breakpilot/ai-compliance-sdk/internal/rbac"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// DraftingHandlers handles Drafting Engine API endpoints
type DraftingHandlers struct {
	accessGate   *llm.AccessGate
	registry     *llm.ProviderRegistry
	piiDetector  *llm.PIIDetector
	auditStore   *audit.Store
	trailBuilder *audit.TrailBuilder
}

// NewDraftingHandlers creates new Drafting Engine handlers
func NewDraftingHandlers(
	accessGate *llm.AccessGate,
	registry *llm.ProviderRegistry,
	piiDetector *llm.PIIDetector,
	auditStore *audit.Store,
	trailBuilder *audit.TrailBuilder,
) *DraftingHandlers {
	return &DraftingHandlers{
		accessGate:   accessGate,
		registry:     registry,
		piiDetector:  piiDetector,
		auditStore:   auditStore,
		trailBuilder: trailBuilder,
	}
}

// ---------------------------------------------------------------------------
// Request/Response Types
// ---------------------------------------------------------------------------

// DraftDocumentRequest represents a request to generate a compliance document draft
type DraftDocumentRequest struct {
	DocumentType string                 `json:"document_type" binding:"required"`
	ScopeLevel   string                 `json:"scope_level" binding:"required"`
	Context      map[string]interface{} `json:"context"`
	Instructions string                 `json:"instructions"`
	Model        string                 `json:"model"`
}

// ValidateDocumentRequest represents a request to validate document consistency
type ValidateDocumentRequest struct {
	DocumentType      string                 `json:"document_type" binding:"required"`
	DraftContent      string                 `json:"draft_content"`
	ValidationContext map[string]interface{} `json:"validation_context"`
	Model             string                 `json:"model"`
}

// DraftHistoryEntry represents a single audit trail entry for drafts
type DraftHistoryEntry struct {
	ID                   string    `json:"id"`
	UserID               string    `json:"user_id"`
	TenantID             string    `json:"tenant_id"`
	DocumentType         string    `json:"document_type"`
	ScopeLevel           string    `json:"scope_level"`
	Operation            string    `json:"operation"`
	ConstraintsRespected bool      `json:"constraints_respected"`
	TokensUsed           int       `json:"tokens_used"`
	CreatedAt            time.Time `json:"created_at"`
}

// ---------------------------------------------------------------------------
// Handlers
// ---------------------------------------------------------------------------

// DraftDocument handles document draft generation via LLM with constraint validation
func (h *DraftingHandlers) DraftDocument(c *gin.Context) {
	var req DraftDocumentRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	userID := rbac.GetUserID(c)
	tenantID := rbac.GetTenantID(c)
	namespaceID := rbac.GetNamespaceID(c)

	if userID == uuid.Nil || tenantID == uuid.Nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "authentication required"})
		return
	}

	// Validate scope level
	validLevels := map[string]bool{"L1": true, "L2": true, "L3": true, "L4": true}
	if !validLevels[req.ScopeLevel] {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid scope_level, must be L1-L4"})
		return
	}

	// Validate document type
	validTypes := map[string]bool{
		"vvt": true, "tom": true, "dsfa": true, "dsi": true, "lf": true,
		"av_vertrag": true, "betroffenenrechte": true, "einwilligung": true,
		"daten_transfer": true, "datenpannen": true, "vertragsmanagement": true,
		"schulung": true, "audit_log": true, "risikoanalyse": true,
		"notfallplan": true, "zertifizierung": true, "datenschutzmanagement": true,
	}
	if !validTypes[req.DocumentType] {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid document_type"})
		return
	}

	// Build system prompt for drafting
	systemPrompt := fmt.Sprintf(
		`Du bist ein DSGVO-Compliance-Experte. Erstelle einen strukturierten Entwurf fuer Dokument "%s" auf Level %s.
Antworte NUR im JSON-Format mit einem "sections" Array.
Jede Section hat: id, title, content, schemaField.
Halte die Tiefe strikt am vorgegebenen Level.
Markiere fehlende Informationen mit [PLATZHALTER: Beschreibung].
Sprache: Deutsch.`,
		req.DocumentType, req.ScopeLevel,
	)

	userPrompt := "Erstelle den Dokumententwurf."
	if req.Instructions != "" {
		userPrompt = req.Instructions
	}

	// Detect PII in context
	contextStr := fmt.Sprintf("%v", req.Context)
	dataCategories := h.piiDetector.DetectDataCategories(contextStr)

	// Process through access gate
	chatReq := &llm.ChatRequest{
		Model: req.Model,
		Messages: []llm.Message{
			{Role: "system", Content: systemPrompt},
			{Role: "user", Content: userPrompt},
		},
		MaxTokens:   16384,
		Temperature: 0.15,
	}

	gatedReq, err := h.accessGate.ProcessChatRequest(
		c.Request.Context(),
		userID, tenantID, namespaceID,
		chatReq, dataCategories,
	)
	if err != nil {
		h.logDraftAudit(c, userID, tenantID, req.DocumentType, req.ScopeLevel, "draft", false, 0, err.Error())
		c.JSON(http.StatusForbidden, gin.H{
			"error":   "access_denied",
			"message": err.Error(),
		})
		return
	}

	// Execute the request
	resp, err := h.accessGate.ExecuteChat(c.Request.Context(), gatedReq)
	if err != nil {
		h.logDraftAudit(c, userID, tenantID, req.DocumentType, req.ScopeLevel, "draft", false, 0, err.Error())
		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   "llm_error",
			"message": err.Error(),
		})
		return
	}

	tokensUsed := 0
	if resp.Usage.TotalTokens > 0 {
		tokensUsed = resp.Usage.TotalTokens
	}

	// Log successful draft
	h.logDraftAudit(c, userID, tenantID, req.DocumentType, req.ScopeLevel, "draft", true, tokensUsed, "")

	c.JSON(http.StatusOK, gin.H{
		"document_type": req.DocumentType,
		"scope_level":   req.ScopeLevel,
		"content":       resp.Message.Content,
		"model":         resp.Model,
		"provider":      resp.Provider,
		"tokens_used":   tokensUsed,
		"pii_detected":  gatedReq.PIIDetected,
	})
}

// ValidateDocument handles document cross-consistency validation
func (h *DraftingHandlers) ValidateDocument(c *gin.Context) {
	var req ValidateDocumentRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	userID := rbac.GetUserID(c)
	tenantID := rbac.GetTenantID(c)
	namespaceID := rbac.GetNamespaceID(c)

	if userID == uuid.Nil || tenantID == uuid.Nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "authentication required"})
		return
	}

	// Build validation prompt
	systemPrompt := `Du bist ein DSGVO-Compliance-Validator. Pruefe die Konsistenz und Vollstaendigkeit.
Antworte NUR im JSON-Format:
{
  "passed": boolean,
  "errors": [{"id": string, "severity": "error", "title": string, "description": string, "documentType": string, "legalReference": string}],
  "warnings": [{"id": string, "severity": "warning", "title": string, "description": string}],
  "suggestions": [{"id": string, "severity": "suggestion", "title": string, "description": string, "suggestion": string}]
}`

	validationPrompt := fmt.Sprintf("Validiere Dokument '%s'.\nInhalt:\n%s\nKontext:\n%v",
		req.DocumentType, req.DraftContent, req.ValidationContext)

	// Detect PII
	dataCategories := h.piiDetector.DetectDataCategories(req.DraftContent)

	chatReq := &llm.ChatRequest{
		Model: req.Model,
		Messages: []llm.Message{
			{Role: "system", Content: systemPrompt},
			{Role: "user", Content: validationPrompt},
		},
		MaxTokens:   8192,
		Temperature: 0.1,
	}

	gatedReq, err := h.accessGate.ProcessChatRequest(
		c.Request.Context(),
		userID, tenantID, namespaceID,
		chatReq, dataCategories,
	)
	if err != nil {
		h.logDraftAudit(c, userID, tenantID, req.DocumentType, "", "validate", false, 0, err.Error())
		c.JSON(http.StatusForbidden, gin.H{
			"error":   "access_denied",
			"message": err.Error(),
		})
		return
	}

	resp, err := h.accessGate.ExecuteChat(c.Request.Context(), gatedReq)
	if err != nil {
		h.logDraftAudit(c, userID, tenantID, req.DocumentType, "", "validate", false, 0, err.Error())
		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   "llm_error",
			"message": err.Error(),
		})
		return
	}

	tokensUsed := 0
	if resp.Usage.TotalTokens > 0 {
		tokensUsed = resp.Usage.TotalTokens
	}

	h.logDraftAudit(c, userID, tenantID, req.DocumentType, "", "validate", true, tokensUsed, "")

	c.JSON(http.StatusOK, gin.H{
		"document_type": req.DocumentType,
		"validation":    resp.Message.Content,
		"model":         resp.Model,
		"provider":      resp.Provider,
		"tokens_used":   tokensUsed,
		"pii_detected":  gatedReq.PIIDetected,
	})
}

// GetDraftHistory returns the audit trail of all drafting operations for a tenant
func (h *DraftingHandlers) GetDraftHistory(c *gin.Context) {
	userID := rbac.GetUserID(c)
	tenantID := rbac.GetTenantID(c)

	if userID == uuid.Nil || tenantID == uuid.Nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "authentication required"})
		return
	}

	// Query audit store for drafting operations
	entries, _, err := h.auditStore.QueryGeneralAuditEntries(c.Request.Context(), &audit.GeneralAuditFilter{
		TenantID:     tenantID,
		ResourceType: "compliance_document",
		Limit:        50,
	})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to query draft history"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"history": entries,
		"total":   len(entries),
	})
}

// ---------------------------------------------------------------------------
// Audit Logging
// ---------------------------------------------------------------------------

func (h *DraftingHandlers) logDraftAudit(
	c *gin.Context,
	userID, tenantID uuid.UUID,
	documentType, scopeLevel, operation string,
	constraintsRespected bool,
	tokensUsed int,
	errorMsg string,
) {
	newValues := map[string]any{
		"document_type":        documentType,
		"scope_level":          scopeLevel,
		"constraints_respected": constraintsRespected,
		"tokens_used":          tokensUsed,
	}
	if errorMsg != "" {
		newValues["error"] = errorMsg
	}

	entry := h.trailBuilder.NewGeneralEntry().
		WithTenant(tenantID).
		WithUser(userID).
		WithAction("drafting_engine." + operation).
		WithResource("compliance_document", nil).
		WithNewValues(newValues).
		WithClient(c.ClientIP(), c.GetHeader("User-Agent"))

	go func() {
		entry.Save(c.Request.Context())
	}()
}
