package services

import (
	"context"
	"fmt"
	"time"

	"github.com/google/uuid"
	"github.com/jmoiron/sqlx"
)

type DashboardService struct {
	db *sqlx.DB
}

func NewDashboardService(db *sqlx.DB) *DashboardService {
	return &DashboardService{db: db}
}

type DashboardData struct {
	DeadlineSummary      DeadlineSummary       `json:"deadline_summary"`
	CaseSummary          CaseSummary           `json:"case_summary"`
	UpcomingDeadlines    []UpcomingDeadline    `json:"upcoming_deadlines"`
	UpcomingAppointments []UpcomingAppointment `json:"upcoming_appointments"`
	RecentActivity       []RecentActivity      `json:"recent_activity"`
}

type DeadlineSummary struct {
	OverdueCount int `json:"overdue_count" db:"overdue_count"`
	DueThisWeek  int `json:"due_this_week" db:"due_this_week"`
	DueNextWeek  int `json:"due_next_week" db:"due_next_week"`
	OKCount      int `json:"ok_count" db:"ok_count"`
}

type CaseSummary struct {
	ActiveCount  int `json:"active_count" db:"active_count"`
	NewThisMonth int `json:"new_this_month" db:"new_this_month"`
	ClosedCount  int `json:"closed_count" db:"closed_count"`
}

type UpcomingDeadline struct {
	ID         uuid.UUID `json:"id" db:"id"`
	Title      string    `json:"title" db:"title"`
	DueDate    string    `json:"due_date" db:"due_date"`
	CaseID     uuid.UUID `json:"case_id" db:"case_id"`
	CaseNumber string    `json:"case_number" db:"case_number"`
	CaseTitle  string    `json:"case_title" db:"case_title"`
	Status     string    `json:"status" db:"status"`
}

type UpcomingAppointment struct {
	ID         uuid.UUID  `json:"id" db:"id"`
	Title      string     `json:"title" db:"title"`
	StartAt    time.Time  `json:"start_at" db:"start_at"`
	CaseNumber *string    `json:"case_number" db:"case_number"`
	Location   *string    `json:"location" db:"location"`
}

type RecentActivity struct {
	ID         uuid.UUID  `json:"id" db:"id"`
	EventType  *string    `json:"event_type" db:"event_type"`
	Title      string     `json:"title" db:"title"`
	CaseID     uuid.UUID  `json:"case_id" db:"case_id"`
	CaseNumber string     `json:"case_number" db:"case_number"`
	EventDate  *time.Time `json:"event_date" db:"event_date"`
}

func (s *DashboardService) Get(ctx context.Context, tenantID uuid.UUID) (*DashboardData, error) {
	now := time.Now()
	today := now.Format("2006-01-02")
	endOfWeek := now.AddDate(0, 0, 7-int(now.Weekday())).Format("2006-01-02")
	endOfNextWeek := now.AddDate(0, 0, 14-int(now.Weekday())).Format("2006-01-02")
	in7Days := now.AddDate(0, 0, 7).Format("2006-01-02")
	startOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()).Format("2006-01-02")

	data := &DashboardData{}

	// Single query with CTEs for deadline + case summaries
	summaryQuery := `
		WITH deadline_stats AS (
			SELECT
				COUNT(*) FILTER (WHERE due_date < $2 AND status = 'pending') AS overdue_count,
				COUNT(*) FILTER (WHERE due_date >= $2 AND due_date <= $3 AND status = 'pending') AS due_this_week,
				COUNT(*) FILTER (WHERE due_date > $3 AND due_date <= $4 AND status = 'pending') AS due_next_week,
				COUNT(*) FILTER (WHERE due_date > $4 AND status = 'pending') AS ok_count
			FROM deadlines
			WHERE tenant_id = $1
		),
		case_stats AS (
			SELECT
				COUNT(*) FILTER (WHERE status = 'active') AS active_count,
				COUNT(*) FILTER (WHERE created_at >= $5::date AND status != 'archived') AS new_this_month,
				COUNT(*) FILTER (WHERE status IN ('closed', 'archived')) AS closed_count
			FROM cases
			WHERE tenant_id = $1
		)
		SELECT
			ds.overdue_count, ds.due_this_week, ds.due_next_week, ds.ok_count,
			cs.active_count, cs.new_this_month, cs.closed_count
		FROM deadline_stats ds, case_stats cs`

	var summaryRow struct {
		DeadlineSummary
		CaseSummary
	}
	err := s.db.GetContext(ctx, &summaryRow, summaryQuery, tenantID, today, endOfWeek, endOfNextWeek, startOfMonth)
	if err != nil {
		return nil, fmt.Errorf("dashboard summary: %w", err)
	}
	data.DeadlineSummary = summaryRow.DeadlineSummary
	data.CaseSummary = summaryRow.CaseSummary

	// Upcoming deadlines (next 7 days)
	deadlineQuery := `
		SELECT d.id, d.title, d.due_date, d.case_id, c.case_number, c.title AS case_title, d.status
		FROM deadlines d
		JOIN cases c ON c.id = d.case_id AND c.tenant_id = d.tenant_id
		WHERE d.tenant_id = $1 AND d.status = 'pending' AND d.due_date >= $2 AND d.due_date <= $3
		ORDER BY d.due_date ASC`

	data.UpcomingDeadlines = []UpcomingDeadline{}
	if err := s.db.SelectContext(ctx, &data.UpcomingDeadlines, deadlineQuery, tenantID, today, in7Days); err != nil {
		return nil, fmt.Errorf("dashboard upcoming deadlines: %w", err)
	}

	// Upcoming appointments (next 7 days)
	appointmentQuery := `
		SELECT a.id, a.title, a.start_at, c.case_number, a.location
		FROM appointments a
		LEFT JOIN cases c ON c.id = a.case_id AND c.tenant_id = a.tenant_id
		WHERE a.tenant_id = $1 AND a.start_at >= $2::timestamp AND a.start_at < ($2::date + interval '7 days')
		ORDER BY a.start_at ASC`

	data.UpcomingAppointments = []UpcomingAppointment{}
	if err := s.db.SelectContext(ctx, &data.UpcomingAppointments, appointmentQuery, tenantID, now); err != nil {
		return nil, fmt.Errorf("dashboard upcoming appointments: %w", err)
	}

	// Recent activity (last 10 case events)
	activityQuery := `
		SELECT ce.id, ce.event_type, ce.title, ce.case_id, c.case_number, ce.event_date
		FROM case_events ce
		JOIN cases c ON c.id = ce.case_id AND c.tenant_id = ce.tenant_id
		WHERE ce.tenant_id = $1
		ORDER BY COALESCE(ce.event_date, ce.created_at) DESC
		LIMIT 10`

	data.RecentActivity = []RecentActivity{}
	if err := s.db.SelectContext(ctx, &data.RecentActivity, activityQuery, tenantID); err != nil {
		return nil, fmt.Errorf("dashboard recent activity: %w", err)
	}

	return data, nil
}
