package whistleblower

import (
	"crypto/rand"
	"fmt"
	"time"

	"github.com/google/uuid"
)

// ============================================================================
// Constants / Enums
// ============================================================================

// ReportCategory represents the category of a whistleblower report
type ReportCategory string

const (
	ReportCategoryCorruption      ReportCategory = "corruption"
	ReportCategoryFraud           ReportCategory = "fraud"
	ReportCategoryDataProtection  ReportCategory = "data_protection"
	ReportCategoryDiscrimination  ReportCategory = "discrimination"
	ReportCategoryEnvironment     ReportCategory = "environment"
	ReportCategoryCompetition     ReportCategory = "competition"
	ReportCategoryProductSafety   ReportCategory = "product_safety"
	ReportCategoryTaxEvasion      ReportCategory = "tax_evasion"
	ReportCategoryOther           ReportCategory = "other"
)

// ReportStatus represents the status of a whistleblower report
type ReportStatus string

const (
	ReportStatusNew           ReportStatus = "new"
	ReportStatusAcknowledged  ReportStatus = "acknowledged"
	ReportStatusUnderReview   ReportStatus = "under_review"
	ReportStatusInvestigation ReportStatus = "investigation"
	ReportStatusMeasuresTaken ReportStatus = "measures_taken"
	ReportStatusClosed        ReportStatus = "closed"
	ReportStatusRejected      ReportStatus = "rejected"
)

// MessageDirection represents the direction of an anonymous message
type MessageDirection string

const (
	MessageDirectionReporterToAdmin MessageDirection = "reporter_to_admin"
	MessageDirectionAdminToReporter MessageDirection = "admin_to_reporter"
)

// MeasureStatus represents the status of a corrective measure
type MeasureStatus string

const (
	MeasureStatusPlanned    MeasureStatus = "planned"
	MeasureStatusInProgress MeasureStatus = "in_progress"
	MeasureStatusCompleted  MeasureStatus = "completed"
)

// ============================================================================
// Main Entities
// ============================================================================

// Report represents a whistleblower report (Hinweis) per HinSchG
type Report struct {
	ID              uuid.UUID      `json:"id"`
	TenantID        uuid.UUID      `json:"tenant_id"`
	ReferenceNumber string         `json:"reference_number"` // e.g. "WB-2026-0001"
	AccessKey       string         `json:"access_key,omitempty"` // for anonymous access, only returned once

	// Report content
	Category    ReportCategory `json:"category"`
	Status      ReportStatus   `json:"status"`
	Title       string         `json:"title"`
	Description string         `json:"description"`

	// Reporter info (optional, for non-anonymous reports)
	IsAnonymous   bool    `json:"is_anonymous"`
	ReporterName  *string `json:"reporter_name,omitempty"`
	ReporterEmail *string `json:"reporter_email,omitempty"`
	ReporterPhone *string `json:"reporter_phone,omitempty"`

	// HinSchG deadlines
	ReceivedAt              time.Time  `json:"received_at"`
	DeadlineAcknowledgment  time.Time  `json:"deadline_acknowledgment"`  // 7 days from received_at per HinSchG
	DeadlineFeedback        time.Time  `json:"deadline_feedback"`        // 3 months from received_at per HinSchG

	// Status timestamps
	AcknowledgedAt *time.Time `json:"acknowledged_at,omitempty"`
	ClosedAt       *time.Time `json:"closed_at,omitempty"`

	// Assignment
	AssignedTo *uuid.UUID `json:"assigned_to,omitempty"`

	// Resolution
	Resolution string `json:"resolution,omitempty"`

	// Audit trail (stored as JSONB)
	AuditTrail []AuditEntry `json:"audit_trail"`

	// Timestamps
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

// AnonymousMessage represents a message exchanged between reporter and admin
type AnonymousMessage struct {
	ID        uuid.UUID        `json:"id"`
	ReportID  uuid.UUID        `json:"report_id"`
	Direction MessageDirection `json:"direction"`
	Content   string           `json:"content"`
	SentAt    time.Time        `json:"sent_at"`
	ReadAt    *time.Time       `json:"read_at,omitempty"`
}

// Measure represents a corrective measure taken for a report
type Measure struct {
	ID          uuid.UUID     `json:"id"`
	ReportID    uuid.UUID     `json:"report_id"`
	Title       string        `json:"title"`
	Description string        `json:"description"`
	Status      MeasureStatus `json:"status"`
	Responsible string        `json:"responsible"`
	DueDate     *time.Time    `json:"due_date,omitempty"`
	CompletedAt *time.Time    `json:"completed_at,omitempty"`
	CreatedAt   time.Time     `json:"created_at"`
}

// AuditEntry represents an entry in the audit trail
type AuditEntry struct {
	Timestamp time.Time `json:"timestamp"`
	Action    string    `json:"action"`
	UserID    string    `json:"user_id"`
	Details   string    `json:"details"`
}

// WhistleblowerStatistics contains aggregated statistics for a tenant
type WhistleblowerStatistics struct {
	TotalReports          int            `json:"total_reports"`
	ByStatus              map[string]int `json:"by_status"`
	ByCategory            map[string]int `json:"by_category"`
	OverdueAcknowledgments int           `json:"overdue_acknowledgments"`
	OverdueFeedbacks      int            `json:"overdue_feedbacks"`
	AvgResolutionDays     float64        `json:"avg_resolution_days"`
}

// ============================================================================
// API Request/Response Types
// ============================================================================

// PublicReportSubmission is the request for submitting a report (NO auth required)
type PublicReportSubmission struct {
	Category      ReportCategory `json:"category" binding:"required"`
	Title         string         `json:"title" binding:"required"`
	Description   string         `json:"description" binding:"required"`
	IsAnonymous   bool           `json:"is_anonymous"`
	ReporterName  *string        `json:"reporter_name,omitempty"`
	ReporterEmail *string        `json:"reporter_email,omitempty"`
	ReporterPhone *string        `json:"reporter_phone,omitempty"`
}

// PublicReportResponse is returned after submitting a report (access_key only shown once!)
type PublicReportResponse struct {
	ReferenceNumber string `json:"reference_number"`
	AccessKey       string `json:"access_key"`
}

// ReportUpdateRequest is the request for updating a report (admin)
type ReportUpdateRequest struct {
	Category    ReportCategory `json:"category,omitempty"`
	Status      ReportStatus   `json:"status,omitempty"`
	Title       string         `json:"title,omitempty"`
	Description string         `json:"description,omitempty"`
	AssignedTo  *uuid.UUID     `json:"assigned_to,omitempty"`
}

// AcknowledgeRequest is the request for acknowledging a report
type AcknowledgeRequest struct {
	Message string `json:"message,omitempty"` // optional acknowledgment message to reporter
}

// CloseReportRequest is the request for closing a report
type CloseReportRequest struct {
	Resolution string `json:"resolution" binding:"required"`
}

// AddMeasureRequest is the request for adding a corrective measure
type AddMeasureRequest struct {
	Title       string     `json:"title" binding:"required"`
	Description string     `json:"description"`
	Responsible string     `json:"responsible" binding:"required"`
	DueDate     *time.Time `json:"due_date,omitempty"`
}

// UpdateMeasureRequest is the request for updating a measure
type UpdateMeasureRequest struct {
	Title       string        `json:"title,omitempty"`
	Description string        `json:"description,omitempty"`
	Status      MeasureStatus `json:"status,omitempty"`
	Responsible string        `json:"responsible,omitempty"`
	DueDate     *time.Time    `json:"due_date,omitempty"`
}

// SendMessageRequest is the request for sending an anonymous message
type SendMessageRequest struct {
	Content string `json:"content" binding:"required"`
}

// ReportListResponse is the response for listing reports
type ReportListResponse struct {
	Reports []Report `json:"reports"`
	Total   int      `json:"total"`
}

// ReportFilters defines filters for listing reports
type ReportFilters struct {
	Status   ReportStatus
	Category ReportCategory
	Limit    int
	Offset   int
}

// ============================================================================
// Helper Functions
// ============================================================================

// generateAccessKey generates a random 12-character alphanumeric key
func generateAccessKey() string {
	const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
	b := make([]byte, 12)
	randomBytes := make([]byte, 12)
	rand.Read(randomBytes)
	for i := range b {
		b[i] = charset[int(randomBytes[i])%len(charset)]
	}
	return string(b)
}

// generateReferenceNumber generates a reference number like "WB-2026-0042"
func generateReferenceNumber(year int, sequence int) string {
	return fmt.Sprintf("WB-%d-%04d", year, sequence)
}
