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>
    /// Avalia alertas e pendências críticas do ciclo a partir dos dados agregados. Regras heurísticas; apenas destaque de riscos.
    /// </summary>
    public static class EventCycleAlertController
    {
        /// <summary>Avalia alertas para todos os ciclos (pedidos) e devolve estado por ciclo. Filtra resolvidos.</summary>
        public static List<EventCycleAlertState> EvaluateAllAlerts(
            IReadOnlyList<ProducerOrder> orders,
            IReadOnlyList<SalesOpportunity> opportunities,
            IReadOnlyList<ProposalRecord> proposals,
            IReadOnlyList<SessionRecord> sessions,
            IReadOnlyList<FollowUpTask> followUpTasks)
        {
            var list = new List<EventCycleAlertState>();
            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 = EvaluateAlertsForCycle(order, opp, ses, cycleFollowUps);
                if (state != null)
                    list.Add(state);
            }

            return list;
        }

        /// <summary>Avalia alertas de um ciclo e devolve estado (alertas não resolvidos).</summary>
        public static EventCycleAlertState EvaluateAlertsForCycle(
            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 alerts = new List<EventCycleAlert>();
            var now = DateTime.UtcNow;

            AddAlert(alerts, cycleId, EventCycleAlertCategory.QuestSession, "Sessão Quest não realizada", "Nenhuma sessão Quest associada ao ciclo.", EventCycleAlertSeverity.Warning, false, EventCycleDashboardController.SectionSessaoQuest, "Agendar sessão Quest.", now, session == null || string.IsNullOrEmpty(session.SessionId));
            AddAlert(alerts, cycleId, EventCycleAlertCategory.QuestSession, "Sessão Quest inconclusiva", "Resultado da sessão não definido ou apenas exploração.", EventCycleAlertSeverity.Warning, false, EventCycleDashboardController.SectionSessaoQuest, "Rever resultado da sessão.", now, session != null && (session.FinalDecisionState == WebSessionDecisionState.Unknown || session.FinalDecisionState == WebSessionDecisionState.ExplorationOnly));

            var highPriorityPending = followUpsForOpportunity != null && followUpsForOpportunity.Any(f => !f.IsCompleted && (f.Priority == FollowUpPriority.High || f.Priority == FollowUpPriority.Urgent));
            AddAlert(alerts, cycleId, EventCycleAlertCategory.Commercial, "Follow-up pendente com prioridade alta", "Existe tarefa de follow-up não concluída com prioridade alta ou urgente.", EventCycleAlertSeverity.High, false, EventCycleDashboardController.SectionComercial, "Concluir ou replanejar follow-up.", now, highPriorityPending);

            AddAlert(alerts, cycleId, EventCycleAlertCategory.Producer, "Pedido sem aceite do produtor", "O produtor ainda não aceitou o pedido.", EventCycleAlertSeverity.Critical, true, EventCycleDashboardController.SectionHandoff, "Aguardar aceite ou contactar produtor.", now, order.AcceptanceStatus != ProducerAcceptanceStatus.Accepted);
            AddAlert(alerts, cycleId, EventCycleAlertCategory.Scope, "Escopo não confirmado", "Escopo do pedido ainda não confirmado por ambos.", EventCycleAlertSeverity.High, true, EventCycleDashboardController.SectionProdutor, "Confirmar escopo na secção Escopo.", now, readiness != null && !readiness.IsScopeConfirmed);
            AddAlert(alerts, cycleId, EventCycleAlertCategory.Preparation, "Checklist com pendências obrigatórias", "Há itens obrigatórios do checklist por concluir.", EventCycleAlertSeverity.High, false, EventCycleDashboardController.SectionProdutor, "Concluir itens obrigatórios e confirmar preparação.", now, checklistState != null && checklistState.RequiredItems > 0 && checklistState.CompletedRequiredItems < checklistState.RequiredItems);
            AddAlert(alerts, cycleId, EventCycleAlertCategory.Execution, "Execução pausada", "A execução operacional está pausada.", EventCycleAlertSeverity.Warning, false, EventCycleDashboardController.SectionExecucao, "Retomar execução no painel do produtor.", now, execState != null && execState.ExecutionStatus == ProducerExecutionStatus.Paused);
            AddAlert(alerts, cycleId, EventCycleAlertCategory.Execution, "Execução bloqueada", "A execução está bloqueada (issue/bloqueio reportado).", EventCycleAlertSeverity.Critical, true, EventCycleDashboardController.SectionExecucao, "Resolver bloqueio com o produtor.", now, execState != null && execState.ExecutionStatus == ProducerExecutionStatus.Blocked);
            AddAlert(alerts, cycleId, EventCycleAlertCategory.Execution, "Relatório final pendente", "Execução concluída mas relatório final não gerado/concluído pelo produtor.", EventCycleAlertSeverity.High, false, EventCycleDashboardController.SectionExecucao, "Produtor deve gerar e concluir relatório final.", now, execState != null && execState.IsCompleted && (finalReport == null || !finalReport.ClosedByProducerAt.HasValue));
            AddAlert(alerts, cycleId, EventCycleAlertCategory.FinalAcceptance, "Aceite final do hotel pendente", "Relatório do produtor concluído; aguarda decisão do hotel (aceitar/rejeitar/solicitar ajuste).", EventCycleAlertSeverity.High, false, EventCycleDashboardController.SectionAceiteFinal, "Tomar decisão na secção Aceite final.", now, finalReport != null && finalReport.ClosedByProducerAt.HasValue && (finalAcceptance == null || finalAcceptance.AcceptanceStatus == HotelFinalAcceptanceStatus.PendingReview));
            AddAlert(alerts, cycleId, EventCycleAlertCategory.FinalAcceptance, "Ajuste final solicitado", "O hotel solicitou ajuste final ao produtor.", EventCycleAlertSeverity.Warning, false, EventCycleDashboardController.SectionAceiteFinal, "Produtor deve ajustar e rever; hotel rever depois.", now, finalAcceptance != null && finalAcceptance.NeedsFinalAdjustment);

            var filtered = alerts.Where(a => !ResolvedCycleAlertStore.IsResolved(a.AlertId)).ToList();
            foreach (var a in filtered)
                a.IsResolved = false;

            var state = new EventCycleAlertState
            {
                CycleId = cycleId,
                Alerts = filtered,
                TotalAlerts = filtered.Count,
                BlockingAlerts = filtered.Count(a => a.IsBlocking),
                HighSeverityAlerts = filtered.Count(a => a.Severity == EventCycleAlertSeverity.Critical || a.Severity == EventCycleAlertSeverity.High),
                LastEvaluatedAt = now
            };
            return state;
        }

        public static void MarkAlertResolved(string alertId) => ResolvedCycleAlertStore.MarkResolved(alertId);
        public static void MarkAlertUnresolved(string alertId) => ResolvedCycleAlertStore.MarkUnresolved(alertId);
        public static void ClearResolvedForCycle(string cycleId) => ResolvedCycleAlertStore.ClearResolvedForCycle(cycleId);
        public static void ClearAllResolved() => ResolvedCycleAlertStore.ClearAllResolved();

        private static void AddAlert(List<EventCycleAlert> alerts, string cycleId, EventCycleAlertCategory category, string title, string summary, EventCycleAlertSeverity severity, bool isBlocking, string relatedSectionKey, string suggestedAction, DateTime createdAt, bool whenTrue)
        {
            if (!whenTrue) return;
            var slug = Slug(title);
            var alertId = cycleId + "_" + category + "_" + slug;
            var alert = new EventCycleAlert
            {
                AlertId = alertId,
                CycleId = cycleId,
                Title = title,
                Summary = summary,
                Severity = severity,
                Category = category,
                IsBlocking = isBlocking,
                RelatedSectionKey = relatedSectionKey,
                SuggestedAction = suggestedAction,
                CreatedAt = createdAt,
                IsResolved = false
            };
            alerts.Add(alert);
        }

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

        /// <summary>Totais globais a partir da lista de estados (para strip/HUD).</summary>
        public static void GetTotals(IReadOnlyList<EventCycleAlertState> states, out int totalAlerts, out int criticalAlerts, out int blockingAlerts, out DateTime? lastEvaluated)
        {
            totalAlerts = 0;
            criticalAlerts = 0;
            blockingAlerts = 0;
            lastEvaluated = null;
            if (states == null) return;
            foreach (var s in states)
            {
                totalAlerts += s.TotalAlerts;
                blockingAlerts += s.BlockingAlerts;
                criticalAlerts += s.Alerts?.Count(a => a.Severity == EventCycleAlertSeverity.Critical) ?? 0;
                if (s.LastEvaluatedAt.HasValue && (!lastEvaluated.HasValue || s.LastEvaluatedAt.Value > lastEvaluated.Value))
                    lastEvaluated = s.LastEvaluatedAt;
            }
        }
    }
}
