using System;
using System.Collections.Generic;
using System.Linq;
using EventsAppQuest.Web.Domain;
using EventsAppQuest.Web.Producer.Domain;

namespace EventsAppQuest.Web.Application
{
    /// <summary>
    /// Benchmark interno do ciclo: gera entradas a partir de métricas e closure, compara e identifica padrões. Apenas leitura agregada.
    /// </summary>
    public static class EventCycleBenchmarkController
    {
        private const int MinEntriesForPatterns = 1;

        /// <summary>Gera o estado de benchmark a partir dos dados atuais (métricas e closure).</summary>
        public static EventCycleBenchmarkState BuildBenchmark(
            IReadOnlyList<ProducerOrder> orders,
            IReadOnlyList<SalesOpportunity> opportunities,
            IReadOnlyList<ProposalRecord> proposals,
            IReadOnlyList<SessionRecord> sessions,
            IReadOnlyList<FollowUpTask> followUpTasks)
        {
            var metricsList = EventCycleMetricsController.CalculateMetrics(orders, opportunities, proposals, sessions, followUpTasks);
            var closures = EventCycleClosureController.EvaluateClosure(orders, opportunities, proposals, sessions, followUpTasks);
            var ordersList = orders ?? new List<ProducerOrder>();
            var now = DateTime.UtcNow;

            var entries = new List<EventCycleBenchmarkEntry>();
            foreach (var m in metricsList ?? new List<EventCycleMetricsState>())
            {
                var order = ordersList.FirstOrDefault(o => o.OrderId == m.CycleId);
                var closure = closures?.FirstOrDefault(c => c.CycleId == m.CycleId);
                var entry = new EventCycleBenchmarkEntry
                {
                    CycleId = m.CycleId,
                    SessionId = order?.SessionId,
                    OpportunityId = order?.OpportunityId,
                    OverallCyclePerformanceScore = m.OverallCyclePerformanceScore,
                    PerformanceLabel = m.PerformanceLabel,
                    QuestCompletionSignalScore = m.QuestCompletionSignalScore,
                    CommercialConversionSignalScore = m.CommercialConversionSignalScore,
                    HandoffDelayRiskScore = m.HandoffDelayRiskScore,
                    ProducerResponseScore = m.ProducerResponseScore,
                    ScopeRevisionCount = m.ScopeRevisionCount,
                    CommunicationActivityScore = m.CommunicationActivityScore,
                    PreparationReadinessScore = m.PreparationReadinessScore,
                    ExecutionProgressScore = m.ExecutionProgressScore,
                    FinalAcceptanceCompletionScore = m.FinalAcceptanceCompletionScore,
                    ClosureStatus = closure?.ClosureStatus,
                    Timestamp = m.LastCalculatedAt ?? now
                };
                entries.Add(entry);
            }

            var best = entries.OrderByDescending(e => e.OverallCyclePerformanceScore).FirstOrDefault();
            var lowest = entries.OrderBy(e => e.OverallCyclePerformanceScore).FirstOrDefault();
            var avg = entries.Count > 0 ? entries.Average(e => e.OverallCyclePerformanceScore) : 0;

            var summary = entries.Count == 0
                ? "Nenhum ciclo para comparar."
                : $" {entries.Count} ciclo(s). Média: {avg:F1}. Melhor: {(best != null ? best.OverallCyclePerformanceScore + " (" + best.CycleId + ")" : "—")}. Pior: {(lowest != null ? lowest.OverallCyclePerformanceScore + " (" + lowest.CycleId + ")" : "—")}.";

            var topPatterns = new List<string>();
            var riskPatterns = new List<string>();

            if (entries.Count >= MinEntriesForPatterns)
            {
                if (best != null)
                {
                    if (best.QuestCompletionSignalScore >= 70 && best.HandoffDelayRiskScore >= 80)
                        topPatterns.Add("Ciclos com Quest forte e handoff rápido tendem a performar melhor.");
                    if (best.ExecutionProgressScore >= 80)
                        topPatterns.Add("Execução com menos bloqueios melhora score final.");
                    if (best.CommunicationActivityScore >= 50)
                        topPatterns.Add("Comunicação ativa associada a melhores resultados.");
                    if (best.ScopeRevisionCount == 0 && best.OverallCyclePerformanceScore >= 60)
                        topPatterns.Add("Sem revisões de escopo associado a performance superior.");
                }
                var lowPerformers = entries.Where(e => e.OverallCyclePerformanceScore < 50).ToList();
                var withRevisions = entries.Where(e => e.ScopeRevisionCount > 0).ToList();
                if (withRevisions.Count > 0 && withRevisions.Average(e => e.OverallCyclePerformanceScore) < (entries.Average(e => e.OverallCyclePerformanceScore)))
                    riskPatterns.Add("Ciclos com mais revisões de escopo tendem a performar pior.");
                if (lowPerformers.Any(e => e.ClosureStatus == "Blocked"))
                    riskPatterns.Add("Ciclos bloqueados concentram os piores scores.");
                var withBlocked = entries.Count(e => e.ClosureStatus == "Blocked");
                if (withBlocked > 0)
                    riskPatterns.Add("Alertas bloqueantes e execução bloqueada reduzem score.");
            }

            return new EventCycleBenchmarkState
            {
                Entries = entries,
                BestPerformingEntry = best,
                LowestPerformingEntry = lowest,
                AveragePerformanceScore = avg,
                ComparisonSummary = summary,
                TopPatterns = topPatterns.Distinct().Take(5).ToList(),
                RiskPatterns = riskPatterns.Distinct().Take(5).ToList(),
                LastBenchmarkedAt = now
            };
        }

        /// <summary>Compara uma entrada com a média do benchmark (diferença em pontos).</summary>
        public static int CompareEntryToAverage(EventCycleBenchmarkEntry entry, EventCycleBenchmarkState benchmark)
        {
            if (entry == null || benchmark == null || benchmark.Entries == null || benchmark.Entries.Count == 0)
                return 0;
            return entry.OverallCyclePerformanceScore - (int)Math.Round(benchmark.AveragePerformanceScore);
        }
    }
}
