package automation

import (
	"context"
	"log/slog"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/service/automation/runtime"
	automationstore "github.com/tidbcloud/AgentTeam/internal/store/automation"
)

const (
	AutomationDashboardHealthHealthy   = "healthy"
	AutomationDashboardHealthAttention = "attention"
	AutomationDashboardHealthCritical  = "critical"

	AutomationDashboardSeverityInfo     = "info"
	AutomationDashboardSeverityWarning  = "warning"
	AutomationDashboardSeverityCritical = "critical"
)

type AutomationDashboardMetrics struct {
	ObservedAt    time.Time
	QueueMetrics  automationstore.QueueMetrics
	RunMetrics    automationstore.RunMetrics
	WaitMetrics   automationstore.WaitMetrics
	RunnerMetrics automationstore.RunnerMetrics
	BlobMetrics   automationstore.BlobMetrics
	Reconciler    runtime.ReconcilerStatus
}

type AutomationDashboard struct {
	ObservedAt     time.Time
	Health         AutomationDashboardHealth
	Metrics        AutomationDashboardMetrics
	AttentionItems []AutomationDashboardAttentionItem
}

type AutomationDashboardHealth struct {
	Status     string
	IssueCount int
}

type AutomationDashboardAttentionItem struct {
	Kind       string
	Severity   string
	Count      int64
	TargetPath string
}

func (s *AutomationsService) GetAutomationDashboard(ctx context.Context, workspaceID string, subject string) (AutomationDashboard, error) {
	if err := s.validateScope(workspaceID, subject); err != nil {
		return AutomationDashboard{}, err
	}
	if err := s.automationAuthorizer().CanReadRun(ctx, s.automationAuthorizationRequest(ctx, workspaceID, subject, AutomationAuthorizationRequest{})); err != nil {
		return AutomationDashboard{}, err
	}
	workspaceID = strings.TrimSpace(workspaceID)
	now := s.now()
	metrics, err := s.automationDashboardMetricsAt(ctx, workspaceID, now)
	if err != nil {
		return AutomationDashboard{}, err
	}
	attentionItems := automationDashboardAttentionItems(metrics)
	return AutomationDashboard{
		ObservedAt:     now,
		Health:         automationDashboardHealth(attentionItems),
		Metrics:        metrics,
		AttentionItems: attentionItems,
	}, nil
}

func (s *AutomationsService) automationDashboardMetricsAt(ctx context.Context, workspaceID string, now time.Time) (AutomationDashboardMetrics, error) {
	queueMetrics, err := s.store.QueueMetrics(ctx, workspaceID, now)
	if err != nil {
		slog.WarnContext(ctx, "automation dashboard queue metrics failed", "workspace_id", workspaceID, "error", err)
		return AutomationDashboardMetrics{}, err
	}
	runMetrics, err := s.store.RunMetrics(ctx, workspaceID)
	if err != nil {
		slog.WarnContext(ctx, "automation dashboard run metrics failed", "workspace_id", workspaceID, "error", err)
		return AutomationDashboardMetrics{}, err
	}
	waitMetrics, err := s.store.WaitMetrics(ctx, workspaceID)
	if err != nil {
		slog.WarnContext(ctx, "automation dashboard wait metrics failed", "workspace_id", workspaceID, "error", err)
		return AutomationDashboardMetrics{}, err
	}
	runnerMetrics, err := s.store.RunnerMetrics(ctx, workspaceID, now)
	if err != nil {
		slog.WarnContext(ctx, "automation dashboard runner metrics failed", "workspace_id", workspaceID, "error", err)
		return AutomationDashboardMetrics{}, err
	}
	blobMetrics, err := s.store.BlobMetrics(ctx, workspaceID, now)
	if err != nil {
		slog.WarnContext(ctx, "automation dashboard blob metrics failed", "workspace_id", workspaceID, "error", err)
		return AutomationDashboardMetrics{}, err
	}
	var reconciler runtime.ReconcilerStatus
	if s.reconcilerStatus != nil {
		reconciler = s.reconcilerStatus()
	}
	return AutomationDashboardMetrics{ObservedAt: now, QueueMetrics: queueMetrics, RunMetrics: runMetrics, WaitMetrics: waitMetrics, RunnerMetrics: runnerMetrics, BlobMetrics: blobMetrics, Reconciler: reconciler}, nil
}

func automationDashboardAttentionItems(metrics AutomationDashboardMetrics) []AutomationDashboardAttentionItem {
	candidates := []AutomationDashboardAttentionItem{
		{Kind: "expired_leases", Severity: AutomationDashboardSeverityCritical, Count: metrics.QueueMetrics.ExpiredLeases, TargetPath: "/automations/dashboard"},
		{Kind: "terminal_inconsistent", Severity: AutomationDashboardSeverityCritical, Count: metrics.RunMetrics.TerminalInconsistent, TargetPath: "/automations/dashboard"},
		{Kind: "leaked_active_run_slots", Severity: AutomationDashboardSeverityCritical, Count: metrics.RunMetrics.LeakedActiveSlots, TargetPath: "/automations/dashboard"},
		{Kind: "blocked_runs", Severity: AutomationDashboardSeverityWarning, Count: metrics.RunMetrics.Blocked, TargetPath: "/automations/runs?status=blocked"},
		{Kind: "failed_runs", Severity: AutomationDashboardSeverityWarning, Count: metrics.RunMetrics.Failed, TargetPath: "/automations/runs?status=failed"},
		{Kind: "active_agent_tasks", Severity: AutomationDashboardSeverityWarning, Count: metrics.WaitMetrics.ActiveAgentTasks, TargetPath: "/automations/dashboard"},
		{Kind: "active_event_waits", Severity: AutomationDashboardSeverityInfo, Count: metrics.WaitMetrics.ActiveEventWaits, TargetPath: "/automations/dashboard"},
		{Kind: "expired_sessions", Severity: AutomationDashboardSeverityWarning, Count: metrics.RunnerMetrics.ExpiredSessions, TargetPath: "/automations/dashboard"},
		{Kind: "expired_artifacts", Severity: AutomationDashboardSeverityWarning, Count: metrics.BlobMetrics.ExpiredArtifacts, TargetPath: "/automations/dashboard"},
		{Kind: "reconciler_failures", Severity: AutomationDashboardSeverityCritical, Count: int64(metrics.Reconciler.ConsecutiveFailures), TargetPath: "/automations/dashboard"},
	}
	items := make([]AutomationDashboardAttentionItem, 0, len(candidates))
	for _, item := range candidates {
		if item.Count > 0 {
			items = append(items, item)
		}
	}
	return items
}

func automationDashboardHealth(items []AutomationDashboardAttentionItem) AutomationDashboardHealth {
	status := AutomationDashboardHealthHealthy
	for _, item := range items {
		if item.Severity == AutomationDashboardSeverityCritical {
			status = AutomationDashboardHealthCritical
			break
		}
		if item.Severity == AutomationDashboardSeverityWarning {
			status = AutomationDashboardHealthAttention
		}
	}
	return AutomationDashboardHealth{Status: status, IssueCount: len(items)}
}
