package handlers

import (
	"net/http"
	"time"

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

// WhistleblowerHandlers handles whistleblower HTTP requests
type WhistleblowerHandlers struct {
	store *whistleblower.Store
}

// NewWhistleblowerHandlers creates new whistleblower handlers
func NewWhistleblowerHandlers(store *whistleblower.Store) *WhistleblowerHandlers {
	return &WhistleblowerHandlers{store: store}
}

// ============================================================================
// Public Handlers (NO auth required — for anonymous reporters)
// ============================================================================

// SubmitReport handles public report submission (no auth required)
// POST /sdk/v1/whistleblower/public/submit
func (h *WhistleblowerHandlers) SubmitReport(c *gin.Context) {
	var req whistleblower.PublicReportSubmission
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	tenantIDStr := c.GetHeader("X-Tenant-ID")
	if tenantIDStr == "" {
		tenantIDStr = c.Query("tenant_id")
	}
	if tenantIDStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "tenant_id is required"})
		return
	}

	tenantID, err := uuid.Parse(tenantIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid tenant_id"})
		return
	}

	report := &whistleblower.Report{
		TenantID:    tenantID,
		Category:    req.Category,
		Title:       req.Title,
		Description: req.Description,
		IsAnonymous: req.IsAnonymous,
	}

	if !req.IsAnonymous {
		report.ReporterName = req.ReporterName
		report.ReporterEmail = req.ReporterEmail
		report.ReporterPhone = req.ReporterPhone
	}

	if err := h.store.CreateReport(c.Request.Context(), report); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, whistleblower.PublicReportResponse{
		ReferenceNumber: report.ReferenceNumber,
		AccessKey:       report.AccessKey,
	})
}

// GetReportByAccessKey retrieves a report by access key (for anonymous reporters)
// GET /sdk/v1/whistleblower/public/report?access_key=xxx
func (h *WhistleblowerHandlers) GetReportByAccessKey(c *gin.Context) {
	accessKey := c.Query("access_key")
	if accessKey == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "access_key is required"})
		return
	}

	report, err := h.store.GetReportByAccessKey(c.Request.Context(), accessKey)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if report == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "report not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"reference_number":        report.ReferenceNumber,
		"category":                report.Category,
		"status":                  report.Status,
		"title":                   report.Title,
		"received_at":             report.ReceivedAt,
		"deadline_acknowledgment": report.DeadlineAcknowledgment,
		"deadline_feedback":       report.DeadlineFeedback,
		"acknowledged_at":         report.AcknowledgedAt,
		"closed_at":               report.ClosedAt,
	})
}

// SendPublicMessage allows a reporter to send a message via access key
// POST /sdk/v1/whistleblower/public/message?access_key=xxx
func (h *WhistleblowerHandlers) SendPublicMessage(c *gin.Context) {
	accessKey := c.Query("access_key")
	if accessKey == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "access_key is required"})
		return
	}

	report, err := h.store.GetReportByAccessKey(c.Request.Context(), accessKey)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if report == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "report not found"})
		return
	}

	var req whistleblower.SendMessageRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	msg := &whistleblower.AnonymousMessage{
		ReportID:  report.ID,
		Direction: whistleblower.MessageDirectionReporterToAdmin,
		Content:   req.Content,
	}

	if err := h.store.AddMessage(c.Request.Context(), msg); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"message": msg})
}

// ============================================================================
// Admin Handlers (auth required)
// ============================================================================

// ListReports lists all reports for the tenant
// GET /sdk/v1/whistleblower/reports
func (h *WhistleblowerHandlers) ListReports(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)

	filters := &whistleblower.ReportFilters{
		Limit: 50,
	}

	if status := c.Query("status"); status != "" {
		filters.Status = whistleblower.ReportStatus(status)
	}
	if category := c.Query("category"); category != "" {
		filters.Category = whistleblower.ReportCategory(category)
	}

	reports, total, err := h.store.ListReports(c.Request.Context(), tenantID, filters)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, whistleblower.ReportListResponse{
		Reports: reports,
		Total:   total,
	})
}

// GetReport retrieves a report by ID (admin)
// GET /sdk/v1/whistleblower/reports/:id
func (h *WhistleblowerHandlers) GetReport(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid report ID"})
		return
	}

	report, err := h.store.GetReport(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if report == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "report not found"})
		return
	}

	messages, _ := h.store.ListMessages(c.Request.Context(), id)
	measures, _ := h.store.ListMeasures(c.Request.Context(), id)

	report.AccessKey = ""

	c.JSON(http.StatusOK, gin.H{
		"report":   report,
		"messages": messages,
		"measures": measures,
	})
}

// UpdateReport updates a report
// PUT /sdk/v1/whistleblower/reports/:id
func (h *WhistleblowerHandlers) UpdateReport(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid report ID"})
		return
	}

	report, err := h.store.GetReport(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if report == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "report not found"})
		return
	}

	var req whistleblower.ReportUpdateRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	userID := rbac.GetUserID(c)

	if req.Category != "" {
		report.Category = req.Category
	}
	if req.Status != "" {
		report.Status = req.Status
	}
	if req.Title != "" {
		report.Title = req.Title
	}
	if req.Description != "" {
		report.Description = req.Description
	}
	if req.AssignedTo != nil {
		report.AssignedTo = req.AssignedTo
	}

	report.AuditTrail = append(report.AuditTrail, whistleblower.AuditEntry{
		Timestamp: time.Now().UTC(),
		Action:    "report_updated",
		UserID:    userID.String(),
		Details:   "Report updated by admin",
	})

	if err := h.store.UpdateReport(c.Request.Context(), report); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	report.AccessKey = ""
	c.JSON(http.StatusOK, gin.H{"report": report})
}

// DeleteReport deletes a report
// DELETE /sdk/v1/whistleblower/reports/:id
func (h *WhistleblowerHandlers) DeleteReport(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid report ID"})
		return
	}

	if err := h.store.DeleteReport(c.Request.Context(), id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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