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>
    /// Mapa de dependências do ciclo: nós, ligações causa→efeito e bloqueios. Agregador; usa dashboard, alertas, closure, métricas e SLA.
    /// </summary>
    public static class EventCycleDependencyMapController
    {
        private const string NCommercial = "Commercial";
        private const string NQuestSession = "QuestSession";
        private const string NHandoff = "Handoff";
        private const string NProducerAcceptance = "ProducerAcceptance";
        private const string NScope = "Scope";
        private const string NPreparation = "Preparation";
        private const string NExecution = "Execution";
        private const string NFinalReport = "FinalReport";
        private const string NFinalAcceptance = "FinalAcceptance";
        private const string NCycleClosed = "CycleClosed";

        /// <summary>Constrói o mapa de dependências para todos os ciclos.</summary>
        public static List<EventCycleDependencyMapState> BuildMaps(
            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 list = new List<EventCycleDependencyMapState>();
            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 map = BuildMapForCycle(cycleId, state, alertState, actionPlan, summary, closure, now);
                if (map != null)
                    list.Add(map);
            }

            return list;
        }

        /// <summary>Constrói o mapa de dependências para um ciclo.</summary>
        public static EventCycleDependencyMapState BuildMapForCycle(
            string cycleId,
            EventCycleDashboardState dashboardState,
            EventCycleAlertState alertState,
            EventCycleActionPlanState actionPlanState,
            EventCycleExecutiveSummary executiveSummary,
            EventCycleClosureState closureState,
            DateTime? evaluatedAt = null)
        {
            if (dashboardState == null) return null;
            var now = evaluatedAt ?? DateTime.UtcNow;

            var nodes = new List<EventCycleDependencyNode>();
            var links = new List<EventCycleDependencyLink>();

            var commercialDone = !string.IsNullOrEmpty(dashboardState.OpportunityId) || !string.IsNullOrEmpty(dashboardState.ProposalId);
            AddNode(nodes, NCommercial, "Proposta/Oportunidade", EventCycleDependencyCategory.Commercial, commercialDone, false);
            AddNode(nodes, NQuestSession, "Sessão Quest concluída", EventCycleDependencyCategory.QuestSession, dashboardState.IsQuestSessionDone, !dashboardState.IsQuestSessionDone && commercialDone);
            AddNode(nodes, NHandoff, "Handoff gerado", EventCycleDependencyCategory.Handoff, dashboardState.IsHandoffGenerated, dashboardState.IsQuestSessionDone && !dashboardState.IsHandoffGenerated);
            AddNode(nodes, NProducerAcceptance, "Aceite do produtor", EventCycleDependencyCategory.Producer, dashboardState.IsProducerAccepted, dashboardState.IsHandoffGenerated && !dashboardState.IsProducerAccepted);
            AddNode(nodes, NScope, "Escopo confirmado", EventCycleDependencyCategory.Scope, dashboardState.IsScopeConfirmed, dashboardState.IsProducerAccepted && !dashboardState.IsScopeConfirmed);
            AddNode(nodes, NPreparation, "Preparação confirmada", EventCycleDependencyCategory.Preparation, dashboardState.IsPreparationConfirmed, dashboardState.IsScopeConfirmed && !dashboardState.IsPreparationConfirmed);
            AddNode(nodes, NExecution, "Execução concluída", EventCycleDependencyCategory.Execution, dashboardState.IsExecutionCompleted, dashboardState.IsPreparationConfirmed && !dashboardState.IsExecutionCompleted);
            AddNode(nodes, NFinalReport, "Relatório final gerado", EventCycleDependencyCategory.Execution, dashboardState.IsExecutionCompleted, false);
            AddNode(nodes, NFinalAcceptance, "Aceite final do hotel", EventCycleDependencyCategory.FinalAcceptance, dashboardState.IsFinalAcceptanceDone, dashboardState.IsExecutionCompleted && !dashboardState.IsFinalAcceptanceDone);
            var cycleClosed = closureState?.IsCycleCompleted ?? false;
            AddNode(nodes, NCycleClosed, "Ciclo encerrado", EventCycleDependencyCategory.FinalAcceptance, cycleClosed, false);

            AddLink(links, NCommercial, NQuestSession, EventCycleDependencyType.Requires, commercialDone, dashboardState.IsQuestSessionDone, "Proposta preparada permite agendar sessão Quest.");
            AddLink(links, NQuestSession, NHandoff, EventCycleDependencyType.Requires, dashboardState.IsQuestSessionDone, dashboardState.IsHandoffGenerated, "Sessão Quest concluída permite gerar handoff.");
            AddLink(links, NHandoff, NProducerAcceptance, EventCycleDependencyType.Requires, dashboardState.IsHandoffGenerated, dashboardState.IsProducerAccepted, "Handoff gera pedido; aceite do produtor necessário.");
            AddLink(links, NProducerAcceptance, NScope, EventCycleDependencyType.Requires, dashboardState.IsProducerAccepted, dashboardState.IsScopeConfirmed, "Aceite do produtor permite confirmar escopo.");
            AddLink(links, NScope, NPreparation, EventCycleDependencyType.Requires, dashboardState.IsScopeConfirmed, dashboardState.IsPreparationConfirmed, "Escopo confirmado desbloqueia preparação.");
            AddLink(links, NPreparation, NExecution, EventCycleDependencyType.Requires, dashboardState.IsPreparationConfirmed, dashboardState.IsExecutionStarted, "Preparação confirmada permite iniciar execução.");
            AddLink(links, NExecution, NFinalReport, EventCycleDependencyType.Requires, dashboardState.IsExecutionCompleted, dashboardState.IsExecutionCompleted, "Execução concluída permite relatório final.");
            AddLink(links, NFinalReport, NFinalAcceptance, EventCycleDependencyType.Requires, dashboardState.IsExecutionCompleted, dashboardState.IsFinalAcceptanceDone, "Relatório final aguarda aceite do hotel.");
            AddLink(links, NFinalAcceptance, NCycleClosed, EventCycleDependencyType.Finalizes, dashboardState.IsFinalAcceptanceDone, cycleClosed, "Aceite final encerra o ciclo.");

            var blockingNodes = nodes.Where(n => n.IsBlockingOthers).ToList();
            var blockedLinks = links.Where(l => l.IsCurrentlyBlocked).ToList();
            var mostCritical = blockedLinks.FirstOrDefault(l => l.DependencyType == EventCycleDependencyType.Requires) ?? blockedLinks.FirstOrDefault();

            var summaryParts = new List<string>();
            if (blockingNodes.Count > 0)
                summaryParts.Add($"{blockingNodes.Count} nó(s) bloqueante(s): " + string.Join(", ", blockingNodes.Select(n => n.Title)));
            if (mostCritical != null)
                summaryParts.Add($"Dependência crítica: {mostCritical.FromNodeId} → {mostCritical.ToNodeId} ({mostCritical.ImpactSummary})");
            summaryParts.Add($"Progresso: {nodes.Count(n => n.IsCompleted)}/{nodes.Count} nós concluídos.");

            return new EventCycleDependencyMapState
            {
                CycleId = cycleId,
                Nodes = nodes,
                Links = links,
                BlockingNodes = blockingNodes,
                MostCriticalDependency = mostCritical,
                DependencySummary = string.Join(" | ", summaryParts),
                LastEvaluatedAt = now
            };
        }

        private static void AddNode(List<EventCycleDependencyNode> nodes, string nodeId, string title, EventCycleDependencyCategory category, bool isCompleted, bool isBlockingOthers)
        {
            nodes.Add(new EventCycleDependencyNode
            {
                NodeId = nodeId,
                Title = title,
                Category = category,
                StatusLabel = isCompleted ? "Concluído" : "Pendente",
                IsCompleted = isCompleted,
                IsBlockingOthers = isBlockingOthers,
                Notes = null
            });
        }

        private static void AddLink(List<EventCycleDependencyLink> links, string from, string to, EventCycleDependencyType type, bool fromDone, bool toDone, string impactSummary)
        {
            var isBlocked = fromDone && !toDone;
            links.Add(new EventCycleDependencyLink
            {
                FromNodeId = from,
                ToNodeId = to,
                DependencyType = type,
                ImpactSummary = impactSummary,
                IsCurrentlyBlocked = isBlocked
            });
        }
    }
}
