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>
    /// Plano de recuperação do ciclo: gera estratégia sugerida para casos em risco ou bloqueados. Agregador; usa closure, alertas, ações, resumo, SLA, dependências e gargalos.
    /// </summary>
    public static class EventCycleRecoveryPlanController
    {
        /// <summary>Gera planos de recuperação para todos os ciclos.</summary>
        public static List<EventCycleRecoveryPlanState> GenerateRecoveryPlans(
            IReadOnlyList<ProducerOrder> orders,
            IReadOnlyList<SalesOpportunity> opportunities,
            IReadOnlyList<ProposalRecord> proposals,
            IReadOnlyList<SessionRecord> sessions,
            IReadOnlyList<FollowUpTask> followUpTasks)
        {
            var dashboardStates = EventCycleDashboardController.BuildDashboard(orders, opportunities, proposals, sessions);
            var closures = EventCycleClosureController.EvaluateClosure(orders, opportunities, proposals, sessions, followUpTasks);
            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 slaList = EventCycleSLAController.EvaluateSLA(orders, opportunities, proposals, sessions, followUpTasks);
            var dependencyMaps = EventCycleDependencyMapController.BuildMaps(orders, opportunities, proposals, sessions, followUpTasks);
            var bottleneckStates = EventCycleBottleneckController.EvaluateBottlenecks(orders, opportunities, proposals, sessions, followUpTasks);

            var list = new List<EventCycleRecoveryPlanState>();
            var now = DateTime.UtcNow;

            foreach (var state in dashboardStates)
            {
                var cycleId = state.ProducerOrderId ?? state.CycleId;
                var closure = closures?.FirstOrDefault(c => c.CycleId == 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 sla = slaList?.FirstOrDefault(s => s.CycleId == cycleId);
                var depMap = dependencyMaps?.FirstOrDefault(m => m.CycleId == cycleId);
                var bottleneckState = bottleneckStates?.FirstOrDefault(b => b.CycleId == cycleId);

                var plan = GenerateRecoveryPlanForCycle(cycleId, state, closure, alertState, actionPlan, summary, sla, depMap, bottleneckState, now);
                if (plan != null)
                    list.Add(plan);
            }

            return list;
        }

        /// <summary>Gera plano de recuperação para um ciclo.</summary>
        public static EventCycleRecoveryPlanState GenerateRecoveryPlanForCycle(
            string cycleId,
            EventCycleDashboardState dashboardState,
            EventCycleClosureState closureState,
            EventCycleAlertState alertState,
            EventCycleActionPlanState actionPlanState,
            EventCycleExecutiveSummary executiveSummary,
            EventCycleSLAState slaState,
            EventCycleDependencyMapState dependencyMapState,
            EventCycleBottleneckState bottleneckState,
            DateTime? generatedAt = null)
        {
            if (dashboardState == null) return null;
            var now = generatedAt ?? DateTime.UtcNow;
            var actions = new List<EventCycleRecoveryAction>();

            var isBlocked = closureState?.IsCycleBlocked ?? false;
            var isAtRisk = closureState?.IsCycleAtRisk ?? false;
            var hasBlockingBottlenecks = (bottleneckState?.BlockingBottlenecks?.Count ?? 0) > 0;

            if (closureState != null && isBlocked && !string.IsNullOrEmpty(closureState.ClosingRecommendation))
            {
                var id = $"{cycleId}_Recovery_Closure";
                if (!CompletedRecoveryActionStore.IsCompleted(id))
                    AddRecoveryAction(actions, id, cycleId, "Desbloquear ciclo", closureState.ClosingRecommendation,
                        EventCycleRecoveryPriority.Urgent, EventCycleRecoveryResponsibleRole.HotelAdmin, null,
                        EventCycleDashboardController.SectionAceiteFinal, 95, EventCycleRecoveryEffort.Medium, true,
                        "Ciclo bloqueado: " + (closureState.MainBlockingReason ?? ""), null);
            }

            if (bottleneckState?.BlockingBottlenecks != null)
            {
                var ordered = bottleneckState.BlockingBottlenecks
                    .OrderByDescending(b => b.Severity)
                    .ThenByDescending(b => b.EstimatedUnlockValue)
                    .ToList();
                foreach (var bn in ordered)
                {
                    if (CompletedRecoveryActionStore.IsCompleted(bn.BottleneckId)) continue;
                    var (title, summary, priority, role, sectionKey, impact, effort, immediate) = MapBottleneckToRecovery(bn);
                    var id = $"{cycleId}_Recovery_{bn.BottleneckId}";
                    if (actions.Any(a => a.RelatedBottleneckId == bn.BottleneckId)) continue;
                    AddRecoveryAction(actions, id, cycleId, title, summary, priority, role, bn.BottleneckId, sectionKey, impact, effort, immediate, bn.RootCauseHint, bn.SuggestedResolution);
                }
            }

            if (isAtRisk && !isBlocked && (executiveSummary?.TopRisks?.Count ?? 0) > 0)
            {
                var firstRisk = executiveSummary.TopRisks?.FirstOrDefault();
                if (firstRisk != null)
                {
                    var id = $"{cycleId}_Recovery_CommercialRisk";
                    if (!CompletedRecoveryActionStore.IsCompleted(id) && !actions.Any(a => a.RelatedSectionKey == EventCycleDashboardController.SectionComercial))
                        AddRecoveryAction(actions, id, cycleId, "Reduzir risco comercial", firstRisk.Title + ". Reforçar follow-up, revisar proposta ou agendar nova sessão Quest.",
                            EventCycleRecoveryPriority.High, EventCycleRecoveryResponsibleRole.HotelSales, null,
                            EventCycleDashboardController.SectionComercial, 70, EventCycleRecoveryEffort.Medium, false,
                            "Ciclo em risco; foco comercial.", null);
                }
            }

            if (slaState != null && slaState.DelayRiskLevel >= EventCycleDelaySeverity.Medium && !string.IsNullOrEmpty(slaState.MainDelayReason))
            {
                var id = $"{cycleId}_Recovery_SLA";
                if (!CompletedRecoveryActionStore.IsCompleted(id))
                    AddRecoveryAction(actions, id, cycleId, "Reduzir atraso no ciclo", slaState.MainDelayReason + ". Acelerar etapa em atraso.",
                        slaState.DelayRiskLevel == EventCycleDelaySeverity.Critical ? EventCycleRecoveryPriority.Urgent : EventCycleRecoveryPriority.High,
                        EventCycleRecoveryResponsibleRole.Shared, null, null, 60, EventCycleRecoveryEffort.Medium, slaState.DelayRiskLevel == EventCycleDelaySeverity.Critical,
                        "SLA em atraso.", null);
            }

            actions = actions.OrderByDescending(a => a.Priority).ThenByDescending(a => a.EstimatedRecoveryImpact).ToList();
            var primary = actions.FirstOrDefault();
            var isRecoveryNeeded = actions.Count > 0;
            var confidence = actions.Count <= 2 ? "Alta" : (actions.Count <= 4 ? "Média" : "Baixa");

            var summaryText = !isRecoveryNeeded
                ? "Recuperação não necessária."
                : $"{actions.Count} ação(ões) de recuperação. Principal: {(primary != null ? primary.Title : "—")}. Confiança: {confidence}.";

            return new EventCycleRecoveryPlanState
            {
                CycleId = cycleId,
                RecoveryActions = actions,
                RecoverySummary = summaryText,
                PrimaryRecoveryAction = primary,
                IsRecoveryNeeded = isRecoveryNeeded,
                RecoveryConfidenceLabel = confidence,
                LastGeneratedAt = now
            };
        }

        private static (string title, string summary, EventCycleRecoveryPriority priority, EventCycleRecoveryResponsibleRole role, string sectionKey, int impact, EventCycleRecoveryEffort effort, bool immediate) MapBottleneckToRecovery(EventCycleBottleneck bn)
        {
            switch (bn.Category)
            {
                case EventCycleBottleneckCategory.Commercial:
                case EventCycleBottleneckCategory.QuestSession:
                    return ("Reforçar follow-up ou nova sessão Quest", bn.Summary ?? "Risco comercial ou Quest pendente.", EventCycleRecoveryPriority.High, EventCycleRecoveryResponsibleRole.HotelSales, EventCycleDashboardController.SectionComercial, 75, EventCycleRecoveryEffort.Medium, false);
                case EventCycleBottleneckCategory.Handoff:
                    return ("Gerar handoff ou contactar produtor para aceite", bn.Summary ?? "Handoff pendente.", EventCycleRecoveryPriority.Urgent, EventCycleRecoveryResponsibleRole.HotelSales, EventCycleDashboardController.SectionHandoff, 90, EventCycleRecoveryEffort.Medium, true);
                case EventCycleBottleneckCategory.Scope:
                    return ("Esclarecer escopo e obter aprovação rápida", bn.Summary ?? "Escopo não confirmado.", EventCycleRecoveryPriority.High, EventCycleRecoveryResponsibleRole.HotelAdmin, EventCycleDashboardController.SectionProdutor, 80, EventCycleRecoveryEffort.Small, true);
                case EventCycleBottleneckCategory.Preparation:
                    return ("Concluir checklist e preparação", bn.Summary ?? "Preparação pendente.", EventCycleRecoveryPriority.High, EventCycleRecoveryResponsibleRole.Producer, EventCycleDashboardController.SectionProdutor, 75, EventCycleRecoveryEffort.Medium, false);
                case EventCycleBottleneckCategory.Execution:
                    return ("Resolver bloqueio operacional de execução", bn.Summary ?? "Execução bloqueada.", EventCycleRecoveryPriority.Urgent, EventCycleRecoveryResponsibleRole.Producer, EventCycleDashboardController.SectionExecucao, 85, EventCycleRecoveryEffort.Large, true);
                case EventCycleBottleneckCategory.FinalAcceptance:
                    return ("Revisão final com hotel / decisão de aceite", bn.Summary ?? "Aceite final pendente.", EventCycleRecoveryPriority.Urgent, EventCycleRecoveryResponsibleRole.HotelAdmin, EventCycleDashboardController.SectionAceiteFinal, 92, EventCycleRecoveryEffort.Small, true);
                default:
                    return (bn.Title ?? "Destravar etapa", bn.Summary ?? bn.SuggestedResolution, bn.Severity == EventCycleBottleneckSeverity.Critical ? EventCycleRecoveryPriority.Urgent : EventCycleRecoveryPriority.High, EventCycleRecoveryResponsibleRole.Shared, bn.RelatedSectionKey, bn.EstimatedImpactScore, EventCycleRecoveryEffort.Medium, bn.IsBlocking);
            }
        }

        private static void AddRecoveryAction(List<EventCycleRecoveryAction> list, string id, string cycleId, string title, string summary,
            EventCycleRecoveryPriority priority, EventCycleRecoveryResponsibleRole role, string relatedBottleneckId, string sectionKey,
            int impact, EventCycleRecoveryEffort effort, bool immediate, string notes, string notesSuffix)
        {
            if (list.Any(a => a.RecoveryActionId == id)) return;
            list.Add(new EventCycleRecoveryAction
            {
                RecoveryActionId = id,
                CycleId = cycleId,
                Title = title,
                Summary = summary,
                Priority = priority,
                ResponsibleRole = role,
                RelatedBottleneckId = relatedBottleneckId,
                RelatedSectionKey = sectionKey,
                EstimatedRecoveryImpact = impact,
                EstimatedRecoveryEffort = effort,
                IsImmediateAction = immediate,
                Notes = string.IsNullOrEmpty(notesSuffix) ? notes : (notes + " " + notesSuffix)
            });
        }

        /// <summary>Marca ação de recuperação como concluída (mock).</summary>
        public static void MarkRecoveryActionCompleted(string recoveryActionId) => CompletedRecoveryActionStore.MarkCompleted(recoveryActionId);

        /// <summary>Limpa conclusões de ações do ciclo (mock).</summary>
        public static void ClearCompletedForCycle(string cycleId) => CompletedRecoveryActionStore.ClearCompletedForCycle(cycleId);

        /// <summary>Limpa todas as conclusões de ações de recuperação (mock).</summary>
        public static void ClearAllCompleted() => CompletedRecoveryActionStore.ClearAllCompleted();
    }
}
