package training

import (
	"context"
	"math"

	"github.com/google/uuid"
)

// Escalation level thresholds (days overdue)
const (
	EscalationThresholdL1 = 7   // Reminder to user
	EscalationThresholdL2 = 14  // Notify team lead
	EscalationThresholdL3 = 30  // Notify management
	EscalationThresholdL4 = 45  // Notify compliance officer
)

// EscalationLabels maps levels to human-readable labels
var EscalationLabels = map[int]string{
	0: "Keine Eskalation",
	1: "Erinnerung an Mitarbeiter",
	2: "Benachrichtigung Teamleitung",
	3: "Benachrichtigung Management",
	4: "Benachrichtigung Compliance Officer",
}

// CheckEscalations checks all overdue assignments and escalates as needed
func CheckEscalations(ctx context.Context, store *Store, tenantID uuid.UUID) ([]EscalationResult, error) {
	overdueAssignments, err := store.ListOverdueAssignments(ctx, tenantID)
	if err != nil {
		return nil, err
	}

	var results []EscalationResult
	now := timeNow().UTC()

	for _, assignment := range overdueAssignments {
		daysOverdue := int(math.Floor(now.Sub(assignment.Deadline).Hours() / 24))
		if daysOverdue < 0 {
			continue
		}

		// Determine new escalation level
		newLevel := 0
		if daysOverdue >= EscalationThresholdL4 {
			newLevel = 4
		} else if daysOverdue >= EscalationThresholdL3 {
			newLevel = 3
		} else if daysOverdue >= EscalationThresholdL2 {
			newLevel = 2
		} else if daysOverdue >= EscalationThresholdL1 {
			newLevel = 1
		}

		// Only escalate if the level has increased
		if newLevel <= assignment.EscalationLevel {
			continue
		}

		previousLevel := assignment.EscalationLevel

		// Update the assignment
		nowTime := now
		_, err := store.pool.Exec(ctx, `
			UPDATE training_assignments SET
				escalation_level = $2,
				last_escalation_at = $3,
				status = 'overdue',
				updated_at = $3
			WHERE id = $1
		`, assignment.ID, newLevel, nowTime)
		if err != nil {
			return nil, err
		}

		// Log the escalation
		assignmentID := assignment.ID
		store.LogAction(ctx, &AuditLogEntry{
			TenantID:   tenantID,
			UserID:     &assignment.UserID,
			Action:     AuditActionEscalated,
			EntityType: AuditEntityAssignment,
			EntityID:   &assignmentID,
			Details: map[string]interface{}{
				"previous_level": previousLevel,
				"new_level":      newLevel,
				"days_overdue":   daysOverdue,
				"label":          EscalationLabels[newLevel],
			},
		})

		results = append(results, EscalationResult{
			AssignmentID:    assignment.ID,
			UserID:          assignment.UserID,
			UserName:        assignment.UserName,
			UserEmail:       assignment.UserEmail,
			ModuleTitle:     assignment.ModuleTitle,
			PreviousLevel:   previousLevel,
			NewLevel:        newLevel,
			DaysOverdue:     daysOverdue,
			EscalationLabel: EscalationLabels[newLevel],
		})
	}

	if results == nil {
		results = []EscalationResult{}
	}

	return results, nil
}

// GetOverdueDeadlines returns all overdue assignments with deadline info
func GetOverdueDeadlines(ctx context.Context, store *Store, tenantID uuid.UUID) ([]DeadlineInfo, error) {
	rows, err := store.pool.Query(ctx, `
		SELECT
			ta.id, m.module_code, m.title,
			ta.user_id, ta.user_name, ta.deadline, ta.status,
			EXTRACT(DAY FROM (NOW() - ta.deadline))::INT AS days_overdue
		FROM training_assignments ta
		JOIN training_modules m ON m.id = ta.module_id
		WHERE ta.tenant_id = $1
		AND ta.status IN ('pending', 'in_progress', 'overdue')
		AND ta.deadline < NOW()
		ORDER BY ta.deadline ASC
	`, tenantID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var deadlines []DeadlineInfo
	for rows.Next() {
		var d DeadlineInfo
		var status string

		err := rows.Scan(
			&d.AssignmentID, &d.ModuleCode, &d.ModuleTitle,
			&d.UserID, &d.UserName, &d.Deadline, &status,
			&d.DaysLeft,
		)
		if err != nil {
			return nil, err
		}

		d.Status = AssignmentStatus(status)
		d.DaysLeft = -d.DaysLeft // Negative means overdue
		deadlines = append(deadlines, d)
	}

	if deadlines == nil {
		deadlines = []DeadlineInfo{}
	}

	return deadlines, nil
}

// VerifyCertificate verifies a certificate by checking the assignment status
func VerifyCertificate(ctx context.Context, store *Store, certificateID uuid.UUID) (bool, *TrainingAssignment, error) {
	// Find assignment with this certificate
	var assignmentID uuid.UUID
	err := store.pool.QueryRow(ctx,
		"SELECT id FROM training_assignments WHERE certificate_id = $1",
		certificateID).Scan(&assignmentID)
	if err != nil {
		return false, nil, err
	}

	assignment, err := store.GetAssignment(ctx, assignmentID)
	if err != nil {
		return false, nil, err
	}
	if assignment == nil {
		return false, nil, nil
	}

	return assignment.Status == AssignmentStatusCompleted, assignment, nil
}
