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

namespace EventsAppQuest.Web.Application
{
    /// <summary>
    /// Gera próximos passos recomendados do ciclo a partir do estado agregado. Regras simples; apenas orientação.
    /// </summary>
    public static class EventCycleActionPlanController
    {
        /// <summary>Gera plano de ações para todos os ciclos. Filtra concluídas.</summary>
        public static List<EventCycleActionPlanState> GenerateActionPlans(
            IReadOnlyList<ProducerOrder> orders,
            IReadOnlyList<SalesOpportunity> opportunities,
            IReadOnlyList<ProposalRecord> proposals,
            IReadOnlyList<SessionRecord> sessions,
            IReadOnlyList<FollowUpTask> followUpTasks)
        {
            var list = new List<EventCycleActionPlanState>();
            if (orders == null) return list;
            var opps = opportunities ?? new List<SalesOpportunity>();
            var sess = sessions ?? new List<SessionRecord>();
            var followUps = followUpTasks ?? new List<FollowUpTask>();

            foreach (var order in orders)
            {
                SalesOpportunity opp = null;
                if (!string.IsNullOrEmpty(order.OpportunityId))
                    opp = opps.FirstOrDefault(o => o.Id == order.OpportunityId);
                SessionRecord ses = null;
                var sessId = order.SessionId ?? opp?.SessionRecordId;
                if (!string.IsNullOrEmpty(sessId))
                    ses = sess.FirstOrDefault(s => s.Id == sessId);
                var cycleFollowUps = followUps.Where(f => f.OpportunityId == order.OpportunityId).ToList();

                var state = GenerateActionPlanForCycle(order, opp, ses, cycleFollowUps);
                if (state != null)
                    list.Add(state);
            }

            return list;
        }

        /// <summary>Gera plano de ações para um ciclo.</summary>
        public static EventCycleActionPlanState GenerateActionPlanForCycle(
            ProducerOrder order,
            SalesOpportunity opportunity,
            SessionRecord session,
            IReadOnlyList<FollowUpTask> followUpsForOpportunity)
        {
            if (order == null) return null;
            var orderId = order.OrderId;
            var cycleId = orderId;
            var readiness = ProducerExecutionReadinessController.Evaluate(orderId);
            var checklistState = ProducerPreparationChecklistController.GetChecklistState(orderId);
            var prepConfirmed = PreparationChecklistStore.IsPreparationConfirmed(orderId);
            var execState = ProducerExecutionTrackingController.GetState(orderId);
            var finalReport = ProducerExecutionFinalReportController.GetReport(orderId);
            var finalAcceptance = HotelFinalAcceptanceController.GetState(orderId);

            var actions = new List<EventCycleRecommendedAction>();
            var now = DateTime.UtcNow;

            if (finalAcceptance != null && finalAcceptance.IsOrderCycleClosed)
            {
                AddAction(actions, cycleId, EventCycleActionType.CloseCycle, "Ciclo encerrado", "O ciclo foi formalmente encerrado.", EventCycleActionPriority.Low, EventCycleResponsibleRole.HotelAdmin, EventCycleDashboardController.SectionAceiteFinal, "Nenhuma ação pendente.", false, now, true, null);
            }
            else
            {
                if (finalAcceptance != null && (finalAcceptance.AcceptanceStatus == HotelFinalAcceptanceStatus.Accepted || finalAcceptance.AcceptanceStatus == HotelFinalAcceptanceStatus.Rejected))
                    AddAction(actions, cycleId, EventCycleActionType.CloseCycle, "Encerrar ciclo", "Aceite ou rejeição já feita; encerrar formalmente o ciclo.", EventCycleActionPriority.High, EventCycleResponsibleRole.HotelAdmin, EventCycleDashboardController.SectionAceiteFinal, "Decisão já tomada; falta encerrar o ciclo.", false, now, true, null);

                if (finalReport != null && finalReport.ClosedByProducerAt.HasValue && (finalAcceptance == null || finalAcceptance.AcceptanceStatus == HotelFinalAcceptanceStatus.PendingReview || finalAcceptance.AcceptanceStatus == HotelFinalAcceptanceStatus.NeedsAdjustment))
                    AddAction(actions, cycleId, EventCycleActionType.ApproveFinalAcceptance, "Aceite final do hotel", "Relatório do produtor concluído; tomar decisão (aceitar/rejeitar/solicitar ajuste).", EventCycleActionPriority.Critical, EventCycleResponsibleRole.HotelAdmin, EventCycleDashboardController.SectionAceiteFinal, "Relatório aguarda decisão do hotel.", true, now, true, null);

                if (execState != null && execState.IsCompleted && (finalReport == null || !finalReport.ClosedByProducerAt.HasValue))
                    AddAction(actions, cycleId, EventCycleActionType.ReviewFinalReport, "Gerar e concluir relatório final", "Execução concluída; produtor deve gerar relatório e concluir operacionalmente.", EventCycleActionPriority.High, EventCycleResponsibleRole.Producer, EventCycleDashboardController.SectionExecucao, "Execução concluída; falta relatório final.", false, now, true, null);

                if (execState != null && execState.ExecutionStatus == ProducerExecutionStatus.Blocked)
                    AddAction(actions, cycleId, EventCycleActionType.ResolveIssue, "Resolver bloqueio da execução", "Execução bloqueada; resolver issue/bloqueio com o produtor.", EventCycleActionPriority.Critical, EventCycleResponsibleRole.Producer, EventCycleDashboardController.SectionExecucao, "Bloqueio reportado na execução.", true, now, true, null);

                if (execState != null && execState.ExecutionStatus == ProducerExecutionStatus.Paused)
                    AddAction(actions, cycleId, EventCycleActionType.StartExecution, "Retomar execução", "Execução está pausada; retomar no painel do produtor.", EventCycleActionPriority.High, EventCycleResponsibleRole.Producer, EventCycleDashboardController.SectionExecucao, "Execução pausada.", false, now, true, null);

                if (prepConfirmed && (execState == null || execState.ExecutionStatus == ProducerExecutionStatus.NotStarted || execState.ExecutionStatus == ProducerExecutionStatus.Preparing))
                    AddAction(actions, cycleId, EventCycleActionType.StartExecution, "Iniciar execução", "Preparação confirmada; iniciar execução operacional.", EventCycleActionPriority.High, EventCycleResponsibleRole.Producer, EventCycleDashboardController.SectionExecucao, "Preparação confirmada.", false, now, true, "Start");

                if (checklistState != null && checklistState.RequiredItems > 0 && checklistState.CompletedRequiredItems < checklistState.RequiredItems)
                    AddAction(actions, cycleId, EventCycleActionType.ConfirmPreparation, "Concluir checklist e confirmar preparação", "Há itens obrigatórios por concluir; depois confirmar preparação.", EventCycleActionPriority.High, EventCycleResponsibleRole.Producer, EventCycleDashboardController.SectionProdutor, "Pendências obrigatórias no checklist.", false, now, true, null);

                if (readiness != null && !readiness.IsScopeConfirmed)
                    AddAction(actions, cycleId, EventCycleActionType.ClarifyScope, "Confirmar escopo", "Escopo ainda não confirmado por ambos; clarificar ou aprovar revisão.", EventCycleActionPriority.High, EventCycleResponsibleRole.HotelAdmin, EventCycleDashboardController.SectionProdutor, "Escopo não confirmado.", true, now, true, null);

                if (order.AcceptanceStatus != ProducerAcceptanceStatus.Accepted)
                    AddAction(actions, cycleId, EventCycleActionType.FollowUpClient, "Contactar produtor para aceite", "Pedido aguarda aceite do produtor.", EventCycleActionPriority.Critical, EventCycleResponsibleRole.HotelSales, EventCycleDashboardController.SectionHandoff, "Pedido sem aceite.", true, now, true, "Accept");

                if (session == null || string.IsNullOrEmpty(session.SessionId))
                    AddAction(actions, cycleId, EventCycleActionType.RunQuestSession, "Realizar sessão Quest", "Nenhuma sessão Quest associada; agendar e realizar.", EventCycleActionPriority.Medium, EventCycleResponsibleRole.HotelSales, EventCycleDashboardController.SectionSessaoQuest, "Sessão Quest não realizada.", false, now, true, null);

                var highPriorityPending = followUpsForOpportunity != null && followUpsForOpportunity.Any(f => !f.IsCompleted && (f.Priority == FollowUpPriority.High || f.Priority == FollowUpPriority.Urgent));
                if (highPriorityPending)
                    AddAction(actions, cycleId, EventCycleActionType.FollowUpClient, "Concluir follow-up prioritário", "Existe follow-up não concluído com prioridade alta.", EventCycleActionPriority.High, EventCycleResponsibleRole.HotelSales, EventCycleDashboardController.SectionComercial, "Follow-up pendente alta prioridade.", false, now, true, "FollowUp");
            }

            var filtered = actions.Where(a => !CompletedCycleActionStore.IsCompleted(a.ActionId)).ToList();
            foreach (var a in filtered)
                a.IsCompleted = false;

            EventCycleRecommendedAction top = null;
            foreach (var p in new[] { EventCycleActionPriority.Critical, EventCycleActionPriority.High, EventCycleActionPriority.Medium, EventCycleActionPriority.Low })
            {
                top = filtered.FirstOrDefault(a => a.Priority == p);
                if (top != null) break;
            }

            return new EventCycleActionPlanState
            {
                CycleId = cycleId,
                Actions = filtered,
                TopPriorityAction = top,
                TotalActions = filtered.Count,
                BlockingActions = filtered.Count(a => a.IsBlockingResolution),
                LastGeneratedAt = now
            };
        }

        public static void MarkActionCompleted(string actionId) => CompletedCycleActionStore.MarkCompleted(actionId);
        public static void MarkActionIncomplete(string actionId) => CompletedCycleActionStore.MarkIncomplete(actionId);
        public static void ClearCompletedForCycle(string cycleId) => CompletedCycleActionStore.ClearCompletedForCycle(cycleId);
        public static void ClearAllCompleted() => CompletedCycleActionStore.ClearAllCompleted();

        private static void AddAction(List<EventCycleRecommendedAction> actions, string cycleId, EventCycleActionType actionType, string title, string summary, EventCycleActionPriority priority, EventCycleResponsibleRole role, string relatedSectionKey, string suggestedReason, bool isBlocking, DateTime createdAt, bool whenTrue, string idSuffix)
        {
            if (!whenTrue) return;
            var suffix = idSuffix ?? Slug(title);
            var actionId = cycleId + "_" + actionType + "_" + suffix;
            actions.Add(new EventCycleRecommendedAction
            {
                ActionId = actionId,
                CycleId = cycleId,
                Title = title,
                Summary = summary,
                ActionType = actionType,
                Priority = priority,
                ResponsibleRole = role,
                RelatedSectionKey = relatedSectionKey,
                SuggestedReason = suggestedReason,
                IsBlockingResolution = isBlocking,
                IsCompleted = false,
                CreatedAt = createdAt
            });
        }

        private static string Slug(string title)
        {
            if (string.IsNullOrEmpty(title)) return "action";
            var sb = new StringBuilder();
            foreach (var c in title.Take(30))
                sb.Append(char.IsLetterOrDigit(c) ? c : '_');
            return sb.Length > 0 ? sb.ToString() : "action";
        }

        /// <summary>Totais globais para strip/HUD.</summary>
        public static void GetTotals(IReadOnlyList<EventCycleActionPlanState> plans, out int totalActions, out int blockingActions, out EventCycleRecommendedAction topPriority, out DateTime? lastGenerated)
        {
            totalActions = 0;
            blockingActions = 0;
            topPriority = null;
            lastGenerated = null;
            if (plans == null) return;
            foreach (var p in plans)
            {
                totalActions += p.TotalActions;
                blockingActions += p.BlockingActions;
                if (p.TopPriorityAction != null && (topPriority == null || (int)p.TopPriorityAction.Priority < (int)topPriority.Priority))
                    topPriority = p.TopPriorityAction;
                if (p.LastGeneratedAt.HasValue && (!lastGenerated.HasValue || p.LastGeneratedAt.Value > lastGenerated.Value))
                    lastGenerated = p.LastGeneratedAt;
            }
        }
    }
}
