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

namespace EventsAppQuest.Web.Application
{
    /// <summary>
    /// Análise de gargalos do ciclo: detecta pontos que travam o fluxo e prioriza destravamento. Agregador; usa alertas, plano de ações, closure, mapa de dependências e SLA.
    /// </summary>
    public static class EventCycleBottleneckController
    {
        /// <summary>Avalia gargalos para todos os ciclos.</summary>
        public static List<EventCycleBottleneckState> EvaluateBottlenecks(
            IReadOnlyList<ProducerOrder> orders,
            IReadOnlyList<SalesOpportunity> opportunities,
            IReadOnlyList<ProposalRecord> proposals,
            IReadOnlyList<SessionRecord> sessions,
            IReadOnlyList<FollowUpTask> followUpTasks)
        {
            var dashboardStates = EventCycleDashboardController.BuildDashboard(orders, opportunities, proposals, sessions);
            var alertStates = EventCycleAlertController.EvaluateAllAlerts(orders, opportunities, proposals, sessions, followUpTasks);
            var actionPlans = EventCycleActionPlanController.GenerateActionPlans(orders, opportunities, proposals, sessions, followUpTasks);
            var summaries = EventCycleExecutiveSummaryController.GenerateSummaries(orders, opportunities, proposals, sessions, followUpTasks);
            var closures = EventCycleClosureController.EvaluateClosure(orders, opportunities, proposals, sessions, followUpTasks);
            var dependencyMaps = EventCycleDependencyMapController.BuildMaps(orders, opportunities, proposals, sessions, followUpTasks);
            var slaList = EventCycleSLAController.EvaluateSLA(orders, opportunities, proposals, sessions, followUpTasks);
            var list = new List<EventCycleBottleneckState>();
            var now = DateTime.UtcNow;

            foreach (var state in dashboardStates)
            {
                var cycleId = state.ProducerOrderId ?? state.CycleId;
                var alertState = alertStates?.FirstOrDefault(a => a.CycleId == cycleId);
                var actionPlan = actionPlans?.FirstOrDefault(p => p.CycleId == cycleId);
                var summary = summaries?.FirstOrDefault(s => s.CycleId == cycleId);
                var closure = closures?.FirstOrDefault(c => c.CycleId == cycleId);
                var depMap = dependencyMaps?.FirstOrDefault(m => m.CycleId == cycleId);
                var sla = slaList?.FirstOrDefault(s => s.CycleId == cycleId);
                var bottleneckState = EvaluateBottlenecksForCycle(cycleId, state, alertState, actionPlan, summary, closure, depMap, sla, now);
                if (bottleneckState != null)
                    list.Add(bottleneckState);
            }

            return list;
        }

        /// <summary>Avalia gargalos para um ciclo.</summary>
        public static EventCycleBottleneckState EvaluateBottlenecksForCycle(
            string cycleId,
            EventCycleDashboardState dashboardState,
            EventCycleAlertState alertState,
            EventCycleActionPlanState actionPlanState,
            EventCycleExecutiveSummary executiveSummary,
            EventCycleClosureState closureState,
            EventCycleDependencyMapState dependencyMapState,
            EventCycleSLAState slaState,
            DateTime? evaluatedAt = null)
        {
            if (dashboardState == null) return null;
            var now = evaluatedAt ?? DateTime.UtcNow;
            var bottlenecks = new List<EventCycleBottleneck>();

            if (dependencyMapState != null)
            {
                if (dependencyMapState.MostCriticalDependency != null && dependencyMapState.MostCriticalDependency.IsCurrentlyBlocked)
                {
                    var link = dependencyMapState.MostCriticalDependency;
                    var (cat, sectionKey, title, resolution) = MapDependencyToBottleneck(link.FromNodeId, link.ToNodeId, link.ImpactSummary);
                    var id = $"{cycleId}_Dep_{link.ToNodeId}";
                    if (!ResolvedBottleneckStore.IsResolved(id))
                        AddOrUpdateBottleneck(bottlenecks, id, cycleId, title, link.ImpactSummary, sectionKey, cat, EventCycleBottleneckSeverity.High, 80, 90, "Dependência crítica bloqueada.", resolution, true, now);
                }
                foreach (var node in dependencyMapState.BlockingNodes ?? new List<EventCycleDependencyNode>())
                {
                    var (cat, sectionKey, title, resolution) = MapNodeToBottleneck(node.NodeId, node.Title);
                    var id = $"{cycleId}_{node.NodeId}";
                    if (!ResolvedBottleneckStore.IsResolved(id))
                        AddOrUpdateBottleneck(bottlenecks, id, cycleId, title, node.Title + " pendente.", sectionKey, cat, EventCycleBottleneckSeverity.Medium, 70, 85, "Nó bloqueante no mapa de dependências.", resolution, true, now);
                }
            }

            if (alertState?.Alerts != null)
            {
                foreach (var a in alertState.Alerts.Where(x => x.IsBlocking))
                {
                    var id = $"{cycleId}_Alert_{a.AlertId}";
                    if (!ResolvedBottleneckStore.IsResolved(id))
                    {
                        var severity = a.Severity == EventCycleAlertSeverity.Critical ? EventCycleBottleneckSeverity.Critical : EventCycleBottleneckSeverity.High;
                        AddOrUpdateBottleneck(bottlenecks, id, cycleId, a.Title, a.Summary ?? a.SuggestedAction, a.RelatedSectionKey, EventCycleBottleneckCategory.CrossStage, severity, 75, 88, a.Summary, a.SuggestedAction ?? "Resolver alerta.", true, now);
                    }
                }
            }

            if (closureState != null && closureState.IsCycleBlocked && !string.IsNullOrEmpty(closureState.MainBlockingReason))
            {
                var id = $"{cycleId}_Closure";
                if (!ResolvedBottleneckStore.IsResolved(id))
                    AddOrUpdateBottleneck(bottlenecks, id, cycleId, "Ciclo bloqueado", closureState.MainBlockingReason, EventCycleDashboardController.SectionAceiteFinal, EventCycleBottleneckCategory.FinalAcceptance, EventCycleBottleneckSeverity.Critical, 95, 95, closureState.MainBlockingReason, closureState.ClosingRecommendation ?? "Resolver bloqueio.", true, now);
            }

            if (slaState != null && slaState.DelayRiskLevel >= EventCycleDelaySeverity.Medium && !string.IsNullOrEmpty(slaState.MainDelayReason))
            {
                var id = $"{cycleId}_SLA";
                if (!ResolvedBottleneckStore.IsResolved(id))
                {
                    var severity = slaState.DelayRiskLevel == EventCycleDelaySeverity.Critical ? EventCycleBottleneckSeverity.Critical : (slaState.DelayRiskLevel == EventCycleDelaySeverity.High ? EventCycleBottleneckSeverity.High : EventCycleBottleneckSeverity.Medium);
                    AddOrUpdateBottleneck(bottlenecks, id, cycleId, "Atraso no ciclo", slaState.MainDelayReason, null, EventCycleBottleneckCategory.CrossStage, severity, 60, 70, "SLA em atraso.", "Reduzir tempo no trecho indicado.", false, now);
                }
            }

            if (dashboardState.IsQuestSessionDone && !dashboardState.IsHandoffGenerated)
            {
                var id = $"{cycleId}_Handoff";
                if (!ResolvedBottleneckStore.IsResolved(id) && !bottlenecks.Any(b => b.BottleneckId == id))
                    AddOrUpdateBottleneck(bottlenecks, id, cycleId, "Handoff pendente", "Sessão Quest concluída mas handoff não gerado.", EventCycleDashboardController.SectionHandoff, EventCycleBottleneckCategory.Handoff, EventCycleBottleneckSeverity.High, 85, 90, "Handoff não gerado após Quest.", "Gerar handoff para produtor.", true, now);
            }

            if (dashboardState.IsExecutionCompleted && !dashboardState.IsFinalAcceptanceDone)
            {
                var id = $"{cycleId}_FinalAcceptance";
                if (!ResolvedBottleneckStore.IsResolved(id) && !bottlenecks.Any(b => b.BottleneckId == id))
                    AddOrUpdateBottleneck(bottlenecks, id, cycleId, "Aceite final pendente", "Execução concluída; aguarda aceite do hotel.", EventCycleDashboardController.SectionAceiteFinal, EventCycleBottleneckCategory.FinalAcceptance, EventCycleBottleneckSeverity.High, 90, 92, "Aceite final do hotel pendente.", "Tomar decisão na secção Aceite final.", true, now);
            }

            var blocking = bottlenecks.Where(b => b.IsBlocking).ToList();
            var topPriority = bottlenecks.OrderByDescending(b => b.Severity).ThenByDescending(b => b.EstimatedUnlockValue).FirstOrDefault();

            var summaryText = bottlenecks.Count == 0
                ? "Nenhum gargalo ativo."
                : $"{blocking.Count} gargalo(s) bloqueante(s). Prioritário: {(topPriority != null ? topPriority.Title : "—")}.";

            return new EventCycleBottleneckState
            {
                CycleId = cycleId,
                Bottlenecks = bottlenecks,
                TopPriorityBottleneck = topPriority,
                BlockingBottlenecks = blocking,
                ResolvedBottlenecks = new List<EventCycleBottleneck>(),
                BottleneckSummary = summaryText,
                LastEvaluatedAt = now
            };
        }

        private static (EventCycleBottleneckCategory cat, string sectionKey, string title, string resolution) MapDependencyToBottleneck(string from, string to, string impact)
        {
            if (to == "QuestSession") return (EventCycleBottleneckCategory.QuestSession, EventCycleDashboardController.SectionSessaoQuest, "Sessão Quest pendente", "Agendar e concluir sessão Quest.");
            if (to == "Handoff") return (EventCycleBottleneckCategory.Handoff, EventCycleDashboardController.SectionHandoff, "Handoff pendente", "Gerar handoff para produtor.");
            if (to == "ProducerAcceptance") return (EventCycleBottleneckCategory.Handoff, EventCycleDashboardController.SectionHandoff, "Aceite do produtor pendente", "Contactar produtor para aceite.");
            if (to == "Scope") return (EventCycleBottleneckCategory.Scope, EventCycleDashboardController.SectionProdutor, "Escopo não confirmado", "Confirmar escopo na secção Escopo.");
            if (to == "Preparation") return (EventCycleBottleneckCategory.Preparation, EventCycleDashboardController.SectionProdutor, "Preparação pendente", "Concluir checklist e confirmar preparação.");
            if (to == "Execution" || to == "FinalReport") return (EventCycleBottleneckCategory.Execution, EventCycleDashboardController.SectionExecucao, "Execução/relatório pendente", "Avançar execução ou gerar relatório final.");
            if (to == "FinalAcceptance") return (EventCycleBottleneckCategory.FinalAcceptance, EventCycleDashboardController.SectionAceiteFinal, "Aceite final pendente", "Tomar decisão na secção Aceite final.");
            if (to == "CycleClosed") return (EventCycleBottleneckCategory.FinalAcceptance, EventCycleDashboardController.SectionAceiteFinal, "Ciclo não encerrado", "Concluir aceite e encerrar ciclo.");
            return (EventCycleBottleneckCategory.CrossStage, null, $"{from} → {to}", impact);
        }

        private static (EventCycleBottleneckCategory cat, string sectionKey, string title, string resolution) MapNodeToBottleneck(string nodeId, string title)
        {
            switch (nodeId)
            {
                case "QuestSession": return (EventCycleBottleneckCategory.QuestSession, EventCycleDashboardController.SectionSessaoQuest, title, "Concluir sessão Quest.");
                case "Handoff": return (EventCycleBottleneckCategory.Handoff, EventCycleDashboardController.SectionHandoff, title, "Gerar handoff.");
                case "ProducerAcceptance": return (EventCycleBottleneckCategory.Handoff, EventCycleDashboardController.SectionHandoff, title, "Obter aceite do produtor.");
                case "Scope": return (EventCycleBottleneckCategory.Scope, EventCycleDashboardController.SectionProdutor, title, "Confirmar escopo.");
                case "Preparation": return (EventCycleBottleneckCategory.Preparation, EventCycleDashboardController.SectionProdutor, title, "Confirmar preparação.");
                case "Execution":
                case "FinalReport": return (EventCycleBottleneckCategory.Execution, EventCycleDashboardController.SectionExecucao, title, "Avançar execução ou relatório.");
                case "FinalAcceptance":
                case "CycleClosed": return (EventCycleBottleneckCategory.FinalAcceptance, EventCycleDashboardController.SectionAceiteFinal, title, "Concluir aceite final.");
                default: return (EventCycleBottleneckCategory.Commercial, EventCycleDashboardController.SectionComercial, title, "Resolver etapa comercial.");
            }
        }

        private static void AddOrUpdateBottleneck(List<EventCycleBottleneck> list, string id, string cycleId, string title, string summary, string sectionKey, EventCycleBottleneckCategory category, EventCycleBottleneckSeverity severity, int impactScore, int unlockValue, string rootCause, string resolution, bool isBlocking, DateTime? createdAt)
        {
            var existing = list.FirstOrDefault(b => b.BottleneckId == id);
            if (existing != null)
            {
                if (severity > existing.Severity) existing.Severity = severity;
                if (impactScore > existing.EstimatedImpactScore) existing.EstimatedImpactScore = impactScore;
                if (unlockValue > existing.EstimatedUnlockValue) existing.EstimatedUnlockValue = unlockValue;
                return;
            }
            list.Add(new EventCycleBottleneck
            {
                BottleneckId = id,
                CycleId = cycleId,
                Title = title,
                Summary = summary,
                RelatedSectionKey = sectionKey,
                Severity = severity,
                Category = category,
                EstimatedImpactScore = impactScore,
                EstimatedUnlockValue = unlockValue,
                RootCauseHint = rootCause,
                SuggestedResolution = resolution,
                IsBlocking = isBlocking,
                IsResolved = false,
                CreatedAt = createdAt
            });
        }

        /// <summary>Marca gargalo como resolvido (mock).</summary>
        public static void MarkBottleneckResolved(string bottleneckId) => ResolvedBottleneckStore.MarkResolved(bottleneckId);

        /// <summary>Limpa gargalos resolvidos do ciclo (mock).</summary>
        public static void ClearResolvedForCycle(string cycleId) => ResolvedBottleneckStore.ClearResolvedForCycle(cycleId);

        /// <summary>Limpa todos os gargalos resolvidos (mock).</summary>
        public static void ClearAllResolved() => ResolvedBottleneckStore.ClearAllResolved();
    }
}
