package repository

import (
	"context"
	"fmt"
	"time"

	"github.com/google/uuid"
	"gorm.io/gorm"
)

type AnalyticsRepository struct {
	db *gorm.DB
}

func NewAnalyticsRepository(db *gorm.DB) *AnalyticsRepository {
	return &AnalyticsRepository{db: db}
}

// GetLetterSummaryStats gets overall summary statistics using summary tables for better performance
func (r *AnalyticsRepository) GetLetterSummaryStats(ctx context.Context, startDate, endDate time.Time, userID, departmentID *uuid.UUID) (map[string]interface{}, error) {
	db := DBFromContext(ctx, r.db)
	stats := make(map[string]interface{})

	// Use summary tables for better performance when possible
	if userID == nil && departmentID != nil {
		// Use department_letter_summary for department-specific stats
		query := db.Table("department_letter_summary").
			Where("department_id = ?", *departmentID)
		
		if !startDate.IsZero() {
			query = query.Where("summary_date >= ?", startDate)
		}
		if !endDate.IsZero() {
			query = query.Where("summary_date <= ?", endDate)
		}

		var result struct {
			TotalIncoming     int64   `gorm:"column:total_incoming"`
			TotalOutgoing     int64   `gorm:"column:total_outgoing"`
			PendingOutgoing   int64   `gorm:"column:pending_outgoing"`
			ApprovedOutgoing  int64   `gorm:"column:approved_outgoing"`
			RejectedOutgoing  int64   `gorm:"column:rejected_outgoing"`
			AvgResponseHours  float64 `gorm:"column:avg_response_hours"`
			CompletionRate    float64 `gorm:"column:completion_rate"`
		}

		query.Select(`
			COALESCE(SUM(incoming_count), 0) as total_incoming,
			COALESCE(SUM(outgoing_count), 0) as total_outgoing,
			COALESCE(SUM(pending_outgoing), 0) as pending_outgoing,
			COALESCE(SUM(approved_outgoing), 0) as approved_outgoing,
			COALESCE(SUM(rejected_outgoing), 0) as rejected_outgoing,
			COALESCE(AVG(avg_response_hours), 0) as avg_response_hours,
			COALESCE(AVG(completion_rate), 0) as completion_rate
		`).Scan(&result)

		stats["total_incoming"] = result.TotalIncoming
		stats["total_outgoing"] = result.TotalOutgoing
		stats["total_pending"] = result.PendingOutgoing
		stats["total_approved"] = result.ApprovedOutgoing
		stats["total_rejected"] = result.RejectedOutgoing
		stats["total_archived"] = int64(0) // Calculate separately if needed
		stats["avg_processing_time"] = result.AvgResponseHours
		stats["completion_rate"] = result.CompletionRate
	} else if userID == nil && departmentID == nil {
		// Use letter_summary for overall stats
		query := db.Table("letter_summary")
		
		if !startDate.IsZero() {
			query = query.Where("summary_date >= ?", startDate)
		}
		if !endDate.IsZero() {
			query = query.Where("summary_date <= ?", endDate)
		}

		var result struct {
			TotalIncoming    int64   `gorm:"column:total_incoming"`
			TotalOutgoing    int64   `gorm:"column:total_outgoing"`
			TotalPending     int64   `gorm:"column:total_pending"`
			TotalApproved    int64   `gorm:"column:total_approved"`
			TotalRejected    int64   `gorm:"column:total_rejected"`
			TotalArchived    int64   `gorm:"column:total_archived"`
			TotalSent        int64   `gorm:"column:total_sent"`
			AvgProcessing    float64 `gorm:"column:avg_processing"`
		}

		query.Select(`
			COALESCE(SUM(CASE WHEN letter_type = 'incoming' THEN total_count ELSE 0 END), 0) as total_incoming,
			COALESCE(SUM(CASE WHEN letter_type = 'outgoing' THEN total_count ELSE 0 END), 0) as total_outgoing,
			COALESCE(SUM(pending_count), 0) as total_pending,
			COALESCE(SUM(approved_count), 0) as total_approved,
			COALESCE(SUM(rejected_count), 0) as total_rejected,
			COALESCE(SUM(archived_count), 0) as total_archived,
			COALESCE(SUM(sent_count), 0) as total_sent,
			COALESCE(AVG(avg_processing_hours), 0) as avg_processing
		`).Scan(&result)

		stats["total_incoming"] = result.TotalIncoming
		stats["total_outgoing"] = result.TotalOutgoing
		stats["total_pending"] = result.TotalPending
		stats["total_approved"] = result.TotalApproved
		stats["total_rejected"] = result.TotalRejected
		stats["total_archived"] = result.TotalArchived
		stats["avg_processing_time"] = result.AvgProcessing

		// Calculate completion rate
		completionRate := float64(0)
		if result.TotalOutgoing > 0 {
			completedCount := result.TotalSent + result.TotalArchived
			completionRate = float64(completedCount) / float64(result.TotalOutgoing) * 100
		}
		stats["completion_rate"] = completionRate
	} else {
		// Fall back to original implementation for user-specific queries
		// Base query builders
		incomingQuery := db.Table("letters_incoming").Where("letters_incoming.deleted_at IS NULL")
		outgoingQuery := db.Table("letters_outgoing").Where("letters_outgoing.deleted_at IS NULL")

		// Apply date filters
		if !startDate.IsZero() {
			incomingQuery = incomingQuery.Where("letters_incoming.created_at >= ?", startDate)
			outgoingQuery = outgoingQuery.Where("letters_outgoing.created_at >= ?", startDate)
		}
		if !endDate.IsZero() {
			incomingQuery = incomingQuery.Where("letters_incoming.created_at <= ?", endDate)
			outgoingQuery = outgoingQuery.Where("letters_outgoing.created_at <= ?", endDate)
		}

		// Apply user/department filters for outgoing letters
		if userID != nil {
			outgoingQuery = outgoingQuery.
				Joins("LEFT JOIN letter_outgoing_recipients ON letter_outgoing_recipients.letter_id = letters_outgoing.id").
				Where("letter_outgoing_recipients.user_id = ?", *userID)
		}

		// Count incoming letters
		var totalIncoming int64
		incomingQuery.Count(&totalIncoming)
		stats["total_incoming"] = totalIncoming

		// Count outgoing letters
		var totalOutgoing int64
		outgoingQuery.Count(&totalOutgoing)
		stats["total_outgoing"] = totalOutgoing

		// Count by status - need to clone query for each count
		var pendingCount, approvedCount, rejectedCount, archivedCount int64
		
		db.Table("letters_outgoing").Where("letters_outgoing.deleted_at IS NULL").
			Where("letters_outgoing.status = ?", "pending_approval").
			Joins("LEFT JOIN letter_outgoing_recipients ON letter_outgoing_recipients.letter_id = letters_outgoing.id").
			Where("letter_outgoing_recipients.user_id = ?", *userID).
			Count(&pendingCount)
			
		db.Table("letters_outgoing").Where("letters_outgoing.deleted_at IS NULL").
			Where("letters_outgoing.status = ?", "approved").
			Joins("LEFT JOIN letter_outgoing_recipients ON letter_outgoing_recipients.letter_id = letters_outgoing.id").
			Where("letter_outgoing_recipients.user_id = ?", *userID).
			Count(&approvedCount)
			
		db.Table("letters_outgoing").Where("letters_outgoing.deleted_at IS NULL").
			Where("letters_outgoing.status = ?", "rejected").
			Joins("LEFT JOIN letter_outgoing_recipients ON letter_outgoing_recipients.letter_id = letters_outgoing.id").
			Where("letter_outgoing_recipients.user_id = ?", *userID).
			Count(&rejectedCount)
			
		db.Table("letters_outgoing").Where("letters_outgoing.deleted_at IS NULL").
			Where("letters_outgoing.status = ?", "archived").
			Joins("LEFT JOIN letter_outgoing_recipients ON letter_outgoing_recipients.letter_id = letters_outgoing.id").
			Where("letter_outgoing_recipients.user_id = ?", *userID).
			Count(&archivedCount)

		stats["total_pending"] = pendingCount
		stats["total_approved"] = approvedCount
		stats["total_rejected"] = rejectedCount
		stats["total_archived"] = archivedCount

		// Calculate average processing time
		var avgProcessingTime *float64
		db.Table("letters_outgoing").
			Select("AVG(EXTRACT(EPOCH FROM (letters_outgoing.updated_at - letters_outgoing.created_at))/3600) as avg_hours").
			Where("letters_outgoing.status IN ('approved', 'sent', 'archived')").
			Where("letters_outgoing.deleted_at IS NULL").
			Scan(&avgProcessingTime)

		if avgProcessingTime != nil {
			stats["avg_processing_time"] = *avgProcessingTime
		} else {
			stats["avg_processing_time"] = float64(0)
		}

		// Calculate completion rate
		var completedCount int64
		db.Table("letters_outgoing").Where("letters_outgoing.deleted_at IS NULL").
			Where("letters_outgoing.status IN ('sent', 'archived')").
			Joins("LEFT JOIN letter_outgoing_recipients ON letter_outgoing_recipients.letter_id = letters_outgoing.id").
			Where("letter_outgoing_recipients.user_id = ?", *userID).
			Count(&completedCount)

		completionRate := float64(0)
		if totalOutgoing > 0 {
			completionRate = float64(completedCount) / float64(totalOutgoing) * 100
		}
		stats["completion_rate"] = completionRate
	}

	return stats, nil
}

// GetStatusDistribution gets letter distribution by status
func (r *AnalyticsRepository) GetStatusDistribution(ctx context.Context, startDate, endDate time.Time, userID *uuid.UUID) ([]map[string]interface{}, error) {
	db := DBFromContext(ctx, r.db)
	var results []map[string]interface{}

	query := `
		WITH combined_letters AS (
			SELECT 
				status,
				'incoming' as type,
				COUNT(*) as count
			FROM letters_incoming
			WHERE deleted_at IS NULL
				%s
			GROUP BY status
			
			UNION ALL
			
			SELECT 
				lo.status,
				'outgoing' as type,
				COUNT(DISTINCT lo.id) as count
			FROM letters_outgoing lo
			%s
			WHERE lo.deleted_at IS NULL
				%s
			GROUP BY lo.status
		)
		SELECT 
			status,
			type,
			count,
			ROUND(count * 100.0 / SUM(count) OVER (PARTITION BY type), 2) as percentage
		FROM combined_letters
		ORDER BY type, count DESC
	`

	incomingDateFilter := ""
	outgoingDateFilter := ""
	if !startDate.IsZero() {
		incomingDateFilter += fmt.Sprintf(" AND created_at >= '%s'", startDate.Format("2006-01-02"))
		outgoingDateFilter += fmt.Sprintf(" AND lo.created_at >= '%s'", startDate.Format("2006-01-02"))
	}
	if !endDate.IsZero() {
		incomingDateFilter += fmt.Sprintf(" AND created_at <= '%s'", endDate.Format("2006-01-02"))
		outgoingDateFilter += fmt.Sprintf(" AND lo.created_at <= '%s'", endDate.Format("2006-01-02"))
	}

	joinClause := ""
	userFilter := ""
	if userID != nil {
		joinClause = "LEFT JOIN letter_outgoing_recipients lor ON lor.letter_id = lo.id"
		userFilter = fmt.Sprintf(" AND lor.user_id = '%s'", userID.String())
	}

	query = fmt.Sprintf(query, incomingDateFilter, joinClause, outgoingDateFilter+userFilter)

	if err := db.Raw(query).Scan(&results).Error; err != nil {
		return nil, err
	}

	return results, nil
}

// GetPriorityDistribution gets letter distribution by priority
func (r *AnalyticsRepository) GetPriorityDistribution(ctx context.Context, startDate, endDate time.Time) ([]map[string]interface{}, error) {
	db := DBFromContext(ctx, r.db)
	var results []map[string]interface{}

	query := `
		SELECT 
			p.id as priority_id,
			p.name as priority_name,
			p.level,
			COUNT(lo.id) as count,
			ROUND(COUNT(lo.id) * 100.0 / SUM(COUNT(lo.id)) OVER (), 2) as percentage,
			AVG(EXTRACT(EPOCH FROM (lo.updated_at - lo.created_at))/3600) as avg_response_time
		FROM priorities p
		LEFT JOIN letters_outgoing lo ON lo.priority_id = p.id AND lo.deleted_at IS NULL
		WHERE 1=1
			%s
		GROUP BY p.id, p.name, p.level
		ORDER BY p.level ASC
	`

	dateFilter := ""
	if !startDate.IsZero() {
		dateFilter += fmt.Sprintf(" AND lo.created_at >= '%s'", startDate.Format("2006-01-02"))
	}
	if !endDate.IsZero() {
		dateFilter += fmt.Sprintf(" AND lo.created_at <= '%s'", endDate.Format("2006-01-02"))
	}

	query = fmt.Sprintf(query, dateFilter)

	if err := db.Raw(query).Scan(&results).Error; err != nil {
		return nil, err
	}

	return results, nil
}

// GetDepartmentStats gets statistics per department using summary tables
func (r *AnalyticsRepository) GetDepartmentStats(ctx context.Context, startDate, endDate time.Time) ([]map[string]interface{}, error) {
	db := DBFromContext(ctx, r.db)
	var results []map[string]interface{}

	// First try using summary table for better performance
	query := `
		SELECT 
			d.id as department_id,
			d.name as department_name,
			d.code as department_code,
			COALESCE(SUM(dls.incoming_count), 0) as incoming_count,
			COALESCE(SUM(dls.outgoing_count), 0) as outgoing_count,
			COALESCE(SUM(dls.pending_outgoing), 0) as pending_count,
			COALESCE(AVG(dls.avg_response_hours), 0) as avg_response_time,
			COALESCE(AVG(dls.completion_rate), 0) as completion_rate
		FROM departments d
		LEFT JOIN department_letter_summary dls ON dls.department_id = d.id
		WHERE 1=1
			%s
		GROUP BY d.id, d.name, d.code
		ORDER BY (COALESCE(SUM(dls.incoming_count), 0) + COALESCE(SUM(dls.outgoing_count), 0)) DESC
	`

	dateFilter := ""
	if !startDate.IsZero() {
		dateFilter += fmt.Sprintf(" AND dls.summary_date >= '%s'", startDate.Format("2006-01-02"))
	}
	if !endDate.IsZero() {
		dateFilter += fmt.Sprintf(" AND dls.summary_date <= '%s'", endDate.Format("2006-01-02"))
	}

	query = fmt.Sprintf(query, dateFilter)

	if err := db.Raw(query).Scan(&results).Error; err != nil {
		return nil, err
	}

	// If no results from summary table, fall back to direct query
	if len(results) == 0 {
		fallbackQuery := `
			SELECT 
				d.id as department_id,
				d.name as department_name,
				d.code as department_code,
				COUNT(DISTINCT lir.letter_id) as incoming_count,
				COUNT(DISTINCT lor.letter_id) as outgoing_count,
				COUNT(DISTINCT CASE WHEN lo.status = 'pending_approval' THEN lo.id END) as pending_count,
				COALESCE(AVG(CASE 
					WHEN lo.status IN ('approved', 'sent', 'archived') 
					THEN EXTRACT(EPOCH FROM (lo.updated_at - lo.created_at))/3600 
				END), 0) as avg_response_time,
				CASE 
					WHEN COUNT(DISTINCT lo.id) > 0 
					THEN ROUND(COUNT(DISTINCT CASE WHEN lo.status IN ('sent', 'archived') THEN lo.id END) * 100.0 / COUNT(DISTINCT lo.id), 2)
					ELSE 0 
				END as completion_rate
			FROM departments d
			LEFT JOIN letter_incoming_recipients lir ON lir.recipient_department_id = d.id
			LEFT JOIN letter_outgoing_recipients lor ON lor.department_id = d.id
			LEFT JOIN letters_outgoing lo ON lo.id = lor.letter_id AND lo.deleted_at IS NULL
			WHERE 1=1
				%s
			GROUP BY d.id, d.name, d.code
			ORDER BY (COUNT(DISTINCT lir.letter_id) + COUNT(DISTINCT lor.letter_id)) DESC
		`

		fallbackDateFilter := ""
		if !startDate.IsZero() {
			fallbackDateFilter += fmt.Sprintf(" AND (lo.created_at >= '%s' OR lo.created_at IS NULL)", startDate.Format("2006-01-02"))
		}
		if !endDate.IsZero() {
			fallbackDateFilter += fmt.Sprintf(" AND (lo.created_at <= '%s' OR lo.created_at IS NULL)", endDate.Format("2006-01-02"))
		}

		fallbackQuery = fmt.Sprintf(fallbackQuery, fallbackDateFilter)
		
		if err := db.Raw(fallbackQuery).Scan(&results).Error; err != nil {
			return nil, err
		}
	}

	return results, nil
}

// GetMonthlyTrend gets monthly trend data using summary tables for better performance
func (r *AnalyticsRepository) GetMonthlyTrend(ctx context.Context, months int) ([]map[string]interface{}, error) {
	db := DBFromContext(ctx, r.db)
	var results []map[string]interface{}

	// Use summary table for better performance
	query := `
		WITH monthly_aggregated AS (
			SELECT 
				TO_CHAR(summary_date, 'Month') as month,
				EXTRACT(YEAR FROM summary_date) as year,
				EXTRACT(MONTH FROM summary_date) as month_num,
				SUM(CASE WHEN letter_type = 'incoming' THEN total_count ELSE 0 END) as incoming_count,
				SUM(CASE WHEN letter_type = 'outgoing' THEN total_count ELSE 0 END) as outgoing_count,
				SUM(total_count) as total_count
			FROM letter_summary
			WHERE summary_date >= NOW() - INTERVAL '%d months'
			GROUP BY TO_CHAR(summary_date, 'Month'), 
					 EXTRACT(YEAR FROM summary_date), 
					 EXTRACT(MONTH FROM summary_date)
		)
		SELECT 
			month,
			year,
			incoming_count,
			outgoing_count,
			total_count,
			LAG(total_count) OVER (ORDER BY year, month_num) as prev_total
		FROM monthly_aggregated
		ORDER BY year DESC, month_num DESC
		LIMIT %d
	`

	query = fmt.Sprintf(query, months, months)

	if err := db.Raw(query).Scan(&results).Error; err != nil {
		// If summary table is empty, fall back to direct query
		if len(results) == 0 {
			fallbackQuery := `
				WITH monthly_data AS (
					SELECT 
						TO_CHAR(date_trunc('month', created_at), 'Month') as month,
						EXTRACT(YEAR FROM created_at) as year,
						EXTRACT(MONTH FROM created_at) as month_num,
						COUNT(*) as incoming_count,
						0 as outgoing_count
					FROM letters_incoming
					WHERE deleted_at IS NULL
						AND created_at >= NOW() - INTERVAL '%d months'
					GROUP BY date_trunc('month', created_at), EXTRACT(YEAR FROM created_at), EXTRACT(MONTH FROM created_at)
					
					UNION ALL
					
					SELECT 
						TO_CHAR(date_trunc('month', created_at), 'Month') as month,
						EXTRACT(YEAR FROM created_at) as year,
						EXTRACT(MONTH FROM created_at) as month_num,
						0 as incoming_count,
						COUNT(*) as outgoing_count
					FROM letters_outgoing
					WHERE deleted_at IS NULL
						AND created_at >= NOW() - INTERVAL '%d months'
					GROUP BY date_trunc('month', created_at), EXTRACT(YEAR FROM created_at), EXTRACT(MONTH FROM created_at)
				)
				SELECT 
					month,
					year,
					SUM(incoming_count) as incoming_count,
					SUM(outgoing_count) as outgoing_count,
					SUM(incoming_count + outgoing_count) as total_count,
					LAG(SUM(incoming_count + outgoing_count)) OVER (ORDER BY year, month_num) as prev_total
				FROM monthly_data
				GROUP BY month, year, month_num
				ORDER BY year DESC, month_num DESC
				LIMIT %d
			`
			
			fallbackQuery = fmt.Sprintf(fallbackQuery, months, months, months)
			
			if err := db.Raw(fallbackQuery).Scan(&results).Error; err != nil {
				return nil, err
			}
		}
	}

	// Calculate growth rate
	for i := range results {
		if results[i]["prev_total"] != nil {
			prevVal, ok := results[i]["prev_total"].(float64)
			if ok && prevVal > 0 {
				current := getFloat64FromInterface(results[i]["total_count"])
				results[i]["growth_rate"] = ((current - prevVal) / prevVal) * 100
			} else {
				results[i]["growth_rate"] = float64(0)
			}
		} else {
			results[i]["growth_rate"] = float64(0)
		}
		delete(results[i], "prev_total")
	}

	return results, nil
}

// Helper function to safely convert interface{} to float64
func getFloat64FromInterface(v interface{}) float64 {
	if v == nil {
		return 0
	}
	switch val := v.(type) {
	case float64:
		return val
	case int64:
		return float64(val)
	case int:
		return float64(val)
	default:
		return 0
	}
}

// GetTopSenders gets top letter senders
func (r *AnalyticsRepository) GetTopSenders(ctx context.Context, limit int, startDate, endDate time.Time) ([]map[string]interface{}, error) {
	db := DBFromContext(ctx, r.db)
	var results []map[string]interface{}

	query := `
		SELECT 
			u.id as user_id,
			u.name as user_name,
			u.email as user_email,
			COALESCE(d.name, 'No Department') as department,
			COUNT(lo.id) as letter_count,
			AVG(EXTRACT(EPOCH FROM (lo.updated_at - lo.created_at))/3600) as avg_response_time
		FROM users u
		LEFT JOIN letters_outgoing lo ON lo.created_by = u.id
		LEFT JOIN user_department ud ON ud.user_id = u.id
		LEFT JOIN departments d ON d.id = ud.department_id
		WHERE lo.deleted_at IS NULL
			%s
		GROUP BY u.id, u.name, u.email, d.name
		ORDER BY letter_count DESC
		LIMIT %d
	`

	dateFilter := ""
	if !startDate.IsZero() {
		dateFilter += fmt.Sprintf(" AND lo.created_at >= '%s'", startDate.Format("2006-01-02"))
	}
	if !endDate.IsZero() {
		dateFilter += fmt.Sprintf(" AND lo.created_at <= '%s'", endDate.Format("2006-01-02"))
	}

	query = fmt.Sprintf(query, dateFilter, limit)

	if err := db.Raw(query).Scan(&results).Error; err != nil {
		return nil, err
	}

	return results, nil
}

// GetInstitutionStats gets statistics per institution using summary tables
func (r *AnalyticsRepository) GetInstitutionStats(ctx context.Context, startDate, endDate time.Time) ([]map[string]interface{}, error) {
	db := DBFromContext(ctx, r.db)
	var results []map[string]interface{}

	// Use summary table for better performance
	query := `
		SELECT 
			i.id as institution_id,
			i.name as institution_name,
			i.type as institution_type,
			COALESCE(SUM(ils.incoming_sent), 0) as incoming_count,
			COALESCE(SUM(ils.outgoing_received), 0) as outgoing_count,
			COALESCE(SUM(ils.total_correspondence), 0) as total_count,
			MAX(ils.last_activity_at) as last_activity
		FROM institutions i
		LEFT JOIN institution_letter_summary ils ON ils.institution_id = i.id
		WHERE 1=1
			%s
		GROUP BY i.id, i.name, i.type
		HAVING COALESCE(SUM(ils.total_correspondence), 0) > 0
		ORDER BY total_count DESC
	`

	dateFilter := ""
	if !startDate.IsZero() {
		dateFilter += fmt.Sprintf(" AND ils.summary_date >= '%s'", startDate.Format("2006-01-02"))
	}
	if !endDate.IsZero() {
		dateFilter += fmt.Sprintf(" AND ils.summary_date <= '%s'", endDate.Format("2006-01-02"))
	}

	query = fmt.Sprintf(query, dateFilter)

	if err := db.Raw(query).Scan(&results).Error; err != nil {
		return nil, err
	}

	return results, nil
}

// GetApprovalMetrics gets approval-related metrics using summary tables
func (r *AnalyticsRepository) GetApprovalMetrics(ctx context.Context, startDate, endDate time.Time) (map[string]interface{}, error) {
	db := DBFromContext(ctx, r.db)
	metrics := make(map[string]interface{})

	// Use summary table for better performance
	query := db.Table("approval_sla_summary")

	if !startDate.IsZero() {
		query = query.Where("summary_date >= ?", startDate)
	}
	if !endDate.IsZero() {
		query = query.Where("summary_date <= ?", endDate)
	}

	var result struct {
		TotalApprovals   int64   `gorm:"column:total_approvals"`
		ApprovedCount    int64   `gorm:"column:approved_count"`
		RejectedCount    int64   `gorm:"column:rejected_count"`
		PendingCount     int64   `gorm:"column:pending_count"`
		AvgApprovalHours float64 `gorm:"column:avg_approval_hours"`
		AvgApprovalSteps float64 `gorm:"column:avg_approval_steps"`
		SLACompliance    float64 `gorm:"column:sla_compliance"`
		WithinSLA        int64   `gorm:"column:within_sla"`
		ExceededSLA      int64   `gorm:"column:exceeded_sla"`
	}

	query.Select(`
		COALESCE(SUM(total_approvals), 0) as total_approvals,
		COALESCE(SUM(approved_count), 0) as approved_count,
		COALESCE(SUM(rejected_count), 0) as rejected_count,
		COALESCE(SUM(pending_count), 0) as pending_count,
		COALESCE(AVG(avg_approval_hours), 0) as avg_approval_hours,
		COALESCE(AVG(avg_approval_steps), 0) as avg_approval_steps,
		COALESCE(AVG(sla_compliance_rate), 0) as sla_compliance,
		COALESCE(SUM(within_sla_count), 0) as within_sla,
		COALESCE(SUM(exceeded_sla_count), 0) as exceeded_sla
	`).Scan(&result)

	metrics["total_submitted"] = result.TotalApprovals
	metrics["total_approved"] = result.ApprovedCount
	metrics["total_rejected"] = result.RejectedCount
	metrics["total_pending"] = result.PendingCount
	metrics["avg_approval_time"] = result.AvgApprovalHours
	metrics["avg_approval_steps"] = result.AvgApprovalSteps
	metrics["sla_compliance_rate"] = result.SLACompliance
	metrics["within_sla_count"] = result.WithinSLA
	metrics["exceeded_sla_count"] = result.ExceededSLA

	// Calculate rates
	if result.TotalApprovals > 0 {
		metrics["approval_rate"] = float64(result.ApprovedCount) / float64(result.TotalApprovals) * 100
		metrics["rejection_rate"] = float64(result.RejectedCount) / float64(result.TotalApprovals) * 100
	} else {
		metrics["approval_rate"] = float64(0)
		metrics["rejection_rate"] = float64(0)
	}

	return metrics, nil
}

// GetDailyActivity gets daily activity data
func (r *AnalyticsRepository) GetDailyActivity(ctx context.Context, days int) ([]map[string]interface{}, error) {
	db := DBFromContext(ctx, r.db)
	var results []map[string]interface{}

	query := `
		WITH daily_data AS (
			SELECT 
				DATE(created_at) as date,
				TO_CHAR(created_at, 'Day') as day_of_week,
				COUNT(CASE WHEN type = 'incoming' THEN 1 END) as incoming_count,
				COUNT(CASE WHEN type = 'outgoing' THEN 1 END) as outgoing_count,
				0 as approved_count,
				0 as rejected_count
			FROM (
				SELECT created_at, 'incoming' as type FROM letters_incoming WHERE deleted_at IS NULL
				UNION ALL
				SELECT created_at, 'outgoing' as type FROM letters_outgoing WHERE deleted_at IS NULL
			) combined
			WHERE created_at >= CURRENT_DATE - INTERVAL '%d days'
			GROUP BY DATE(created_at), TO_CHAR(created_at, 'Day')
		),
		approval_data AS (
			SELECT 
				DATE(acted_at) as date,
				COUNT(CASE WHEN status = 'approved' THEN 1 END) as approved_count,
				COUNT(CASE WHEN status = 'rejected' THEN 1 END) as rejected_count
			FROM letter_outgoing_approvals
			WHERE acted_at IS NOT NULL
				AND acted_at >= CURRENT_DATE - INTERVAL '%d days'
			GROUP BY DATE(acted_at)
		)
		SELECT 
			d.date,
			d.day_of_week,
			d.incoming_count,
			d.outgoing_count,
			COALESCE(a.approved_count, 0) as approved_count,
			COALESCE(a.rejected_count, 0) as rejected_count
		FROM daily_data d
		LEFT JOIN approval_data a ON a.date = d.date
		ORDER BY d.date DESC
		LIMIT %d
	`

	query = fmt.Sprintf(query, days, days, days)

	if err := db.Raw(query).Scan(&results).Error; err != nil {
		return nil, err
	}

	return results, nil
}

// GetResponseTimeStats gets response time statistics
func (r *AnalyticsRepository) GetResponseTimeStats(ctx context.Context, startDate, endDate time.Time) (map[string]interface{}, error) {
	db := DBFromContext(ctx, r.db)
	stats := make(map[string]interface{})

	query := `
		WITH response_times AS (
			SELECT 
				EXTRACT(EPOCH FROM (updated_at - created_at))/3600 as response_time_hours
			FROM letters_outgoing
			WHERE status IN ('approved', 'sent', 'archived')
				AND deleted_at IS NULL
				%s
		)
		SELECT 
			MIN(response_time_hours) as min_response_time,
			MAX(response_time_hours) as max_response_time,
			AVG(response_time_hours) as avg_response_time,
			PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY response_time_hours) as median_response_time,
			PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY response_time_hours) as p95_response_time,
			PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY response_time_hours) as p99_response_time
		FROM response_times
	`

	dateFilter := ""
	if !startDate.IsZero() {
		dateFilter += fmt.Sprintf(" AND created_at >= '%s'", startDate.Format("2006-01-02"))
	}
	if !endDate.IsZero() {
		dateFilter += fmt.Sprintf(" AND created_at <= '%s'", endDate.Format("2006-01-02"))
	}

	query = fmt.Sprintf(query, dateFilter)

	if err := db.Raw(query).Scan(&stats).Error; err != nil {
		return nil, err
	}

	return stats, nil
}
