package handlers

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

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

// AuditHandlers handles audit-related API endpoints
type AuditHandlers struct {
	store    *audit.Store
	exporter *audit.Exporter
}

// NewAuditHandlers creates new audit handlers
func NewAuditHandlers(store *audit.Store, exporter *audit.Exporter) *AuditHandlers {
	return &AuditHandlers{
		store:    store,
		exporter: exporter,
	}
}

// QueryLLMAudit queries LLM audit entries
func (h *AuditHandlers) QueryLLMAudit(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)
	if tenantID == uuid.Nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
		return
	}

	filter := &audit.LLMAuditFilter{
		TenantID: tenantID,
		Limit:    50,
		Offset:   0,
	}

	// Parse query parameters
	if nsID := c.Query("namespace_id"); nsID != "" {
		if id, err := uuid.Parse(nsID); err == nil {
			filter.NamespaceID = &id
		}
	}

	if userID := c.Query("user_id"); userID != "" {
		if id, err := uuid.Parse(userID); err == nil {
			filter.UserID = &id
		}
	}

	if op := c.Query("operation"); op != "" {
		filter.Operation = op
	}

	if model := c.Query("model"); model != "" {
		filter.Model = model
	}

	if pii := c.Query("pii_detected"); pii != "" {
		val := pii == "true"
		filter.PIIDetected = &val
	}

	if violations := c.Query("has_violations"); violations == "true" {
		val := true
		filter.HasViolations = &val
	}

	if startDate := c.Query("start_date"); startDate != "" {
		if t, err := time.Parse(time.RFC3339, startDate); err == nil {
			filter.StartDate = &t
		}
	}

	if endDate := c.Query("end_date"); endDate != "" {
		if t, err := time.Parse(time.RFC3339, endDate); err == nil {
			filter.EndDate = &t
		}
	}

	if limit := c.Query("limit"); limit != "" {
		var l int
		if _, err := parseIntQuery(limit, &l); err == nil && l > 0 && l <= 1000 {
			filter.Limit = l
		}
	}

	if offset := c.Query("offset"); offset != "" {
		var o int
		if _, err := parseIntQuery(offset, &o); err == nil && o >= 0 {
			filter.Offset = o
		}
	}

	entries, total, err := h.store.QueryLLMAuditEntries(c.Request.Context(), filter)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"entries": entries,
		"total":   total,
		"limit":   filter.Limit,
		"offset":  filter.Offset,
	})
}

// QueryGeneralAudit queries general audit entries
func (h *AuditHandlers) QueryGeneralAudit(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)
	if tenantID == uuid.Nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
		return
	}

	filter := &audit.GeneralAuditFilter{
		TenantID: tenantID,
		Limit:    50,
		Offset:   0,
	}

	// Parse query parameters
	if nsID := c.Query("namespace_id"); nsID != "" {
		if id, err := uuid.Parse(nsID); err == nil {
			filter.NamespaceID = &id
		}
	}

	if userID := c.Query("user_id"); userID != "" {
		if id, err := uuid.Parse(userID); err == nil {
			filter.UserID = &id
		}
	}

	if action := c.Query("action"); action != "" {
		filter.Action = action
	}

	if resourceType := c.Query("resource_type"); resourceType != "" {
		filter.ResourceType = resourceType
	}

	if resourceID := c.Query("resource_id"); resourceID != "" {
		if id, err := uuid.Parse(resourceID); err == nil {
			filter.ResourceID = &id
		}
	}

	if startDate := c.Query("start_date"); startDate != "" {
		if t, err := time.Parse(time.RFC3339, startDate); err == nil {
			filter.StartDate = &t
		}
	}

	if endDate := c.Query("end_date"); endDate != "" {
		if t, err := time.Parse(time.RFC3339, endDate); err == nil {
			filter.EndDate = &t
		}
	}

	if limit := c.Query("limit"); limit != "" {
		var l int
		if _, err := parseIntQuery(limit, &l); err == nil && l > 0 && l <= 1000 {
			filter.Limit = l
		}
	}

	if offset := c.Query("offset"); offset != "" {
		var o int
		if _, err := parseIntQuery(offset, &o); err == nil && o >= 0 {
			filter.Offset = o
		}
	}

	entries, total, err := h.store.QueryGeneralAuditEntries(c.Request.Context(), filter)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"entries": entries,
		"total":   total,
		"limit":   filter.Limit,
		"offset":  filter.Offset,
	})
}

// GetUsageStats returns LLM usage statistics
func (h *AuditHandlers) GetUsageStats(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)
	if tenantID == uuid.Nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
		return
	}

	// Default to last 30 days
	endDate := time.Now().UTC()
	startDate := endDate.AddDate(0, 0, -30)

	if sd := c.Query("start_date"); sd != "" {
		if t, err := time.Parse(time.RFC3339, sd); err == nil {
			startDate = t
		}
	}

	if ed := c.Query("end_date"); ed != "" {
		if t, err := time.Parse(time.RFC3339, ed); err == nil {
			endDate = t
		}
	}

	stats, err := h.store.GetLLMUsageStats(c.Request.Context(), tenantID, startDate, endDate)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"period_start": startDate.Format(time.RFC3339),
		"period_end":   endDate.Format(time.RFC3339),
		"stats":        stats,
	})
}

// ExportLLMAudit exports LLM audit entries
func (h *AuditHandlers) ExportLLMAudit(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)
	if tenantID == uuid.Nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
		return
	}

	// Default to last 30 days
	endDate := time.Now().UTC()
	startDate := endDate.AddDate(0, 0, -30)

	if sd := c.Query("start_date"); sd != "" {
		if t, err := time.Parse(time.RFC3339, sd); err == nil {
			startDate = t
		}
	}

	if ed := c.Query("end_date"); ed != "" {
		if t, err := time.Parse(time.RFC3339, ed); err == nil {
			endDate = t
		}
	}

	format := audit.FormatJSON
	if c.Query("format") == "csv" {
		format = audit.FormatCSV
	}

	includePII := c.Query("include_pii") == "true"

	opts := &audit.ExportOptions{
		TenantID:   tenantID,
		StartDate:  startDate,
		EndDate:    endDate,
		Format:     format,
		IncludePII: includePII,
	}

	if nsID := c.Query("namespace_id"); nsID != "" {
		if id, err := uuid.Parse(nsID); err == nil {
			opts.NamespaceID = &id
		}
	}

	if userID := c.Query("user_id"); userID != "" {
		if id, err := uuid.Parse(userID); err == nil {
			opts.UserID = &id
		}
	}

	var buf bytes.Buffer
	if err := h.exporter.ExportLLMAudit(c.Request.Context(), &buf, opts); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Set appropriate content type
	contentType := "application/json"
	ext := "json"
	if format == audit.FormatCSV {
		contentType = "text/csv"
		ext = "csv"
	}

	filename := "llm_audit_" + time.Now().Format("20060102") + "." + ext
	c.Header("Content-Disposition", "attachment; filename="+filename)
	c.Data(http.StatusOK, contentType, buf.Bytes())
}

// ExportGeneralAudit exports general audit entries
func (h *AuditHandlers) ExportGeneralAudit(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)
	if tenantID == uuid.Nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
		return
	}

	endDate := time.Now().UTC()
	startDate := endDate.AddDate(0, 0, -30)

	if sd := c.Query("start_date"); sd != "" {
		if t, err := time.Parse(time.RFC3339, sd); err == nil {
			startDate = t
		}
	}

	if ed := c.Query("end_date"); ed != "" {
		if t, err := time.Parse(time.RFC3339, ed); err == nil {
			endDate = t
		}
	}

	format := audit.FormatJSON
	if c.Query("format") == "csv" {
		format = audit.FormatCSV
	}

	includePII := c.Query("include_pii") == "true"

	opts := &audit.ExportOptions{
		TenantID:   tenantID,
		StartDate:  startDate,
		EndDate:    endDate,
		Format:     format,
		IncludePII: includePII,
	}

	var buf bytes.Buffer
	if err := h.exporter.ExportGeneralAudit(c.Request.Context(), &buf, opts); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	contentType := "application/json"
	ext := "json"
	if format == audit.FormatCSV {
		contentType = "text/csv"
		ext = "csv"
	}

	filename := "general_audit_" + time.Now().Format("20060102") + "." + ext
	c.Header("Content-Disposition", "attachment; filename="+filename)
	c.Data(http.StatusOK, contentType, buf.Bytes())
}

// ExportComplianceReport exports a compliance report
func (h *AuditHandlers) ExportComplianceReport(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)
	if tenantID == uuid.Nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
		return
	}

	endDate := time.Now().UTC()
	startDate := endDate.AddDate(0, 0, -30)

	if sd := c.Query("start_date"); sd != "" {
		if t, err := time.Parse(time.RFC3339, sd); err == nil {
			startDate = t
		}
	}

	if ed := c.Query("end_date"); ed != "" {
		if t, err := time.Parse(time.RFC3339, ed); err == nil {
			endDate = t
		}
	}

	format := audit.FormatJSON
	if c.Query("format") == "csv" {
		format = audit.FormatCSV
	}

	var buf bytes.Buffer
	if err := h.exporter.ExportComplianceReport(c.Request.Context(), &buf, tenantID, startDate, endDate, format); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	contentType := "application/json"
	ext := "json"
	if format == audit.FormatCSV {
		contentType = "text/csv"
		ext = "csv"
	}

	filename := "compliance_report_" + time.Now().Format("20060102") + "." + ext
	c.Header("Content-Disposition", "attachment; filename="+filename)
	c.Data(http.StatusOK, contentType, buf.Bytes())
}

// GetComplianceReport returns a compliance report as JSON (for dashboard)
func (h *AuditHandlers) GetComplianceReport(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)
	if tenantID == uuid.Nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
		return
	}

	endDate := time.Now().UTC()
	startDate := endDate.AddDate(0, 0, -30)

	if sd := c.Query("start_date"); sd != "" {
		if t, err := time.Parse(time.RFC3339, sd); err == nil {
			startDate = t
		}
	}

	if ed := c.Query("end_date"); ed != "" {
		if t, err := time.Parse(time.RFC3339, ed); err == nil {
			endDate = t
		}
	}

	report, err := h.exporter.GenerateComplianceReport(c.Request.Context(), tenantID, startDate, endDate)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, report)
}

// Helper function to parse int from query
func parseIntQuery(s string, out *int) (int, error) {
	var i int
	_, err := fmt.Sscanf(s, "%d", &i)
	if err != nil {
		return 0, err
	}
	*out = i
	return i, nil
}
