using System.Collections.Generic;
using System.Linq;
using EventsAppQuest.Application.Services;
using EventsAppQuest.Core;
using EventsAppQuest.Domain.Models;

namespace EventsAppQuest.Infrastructure.Services
{
    /// <summary>
    /// Avalia fluxo e logística operacional (circulação, gargalos, acesso de serviço) a partir do layout e dos itens da proposta.
    /// </summary>
    public class MockEventFlowEvaluationService : IEventFlowEvaluationService
    {
        public EventFlowEvaluationResult Evaluate(EventProject project, EventProjectProposal proposal)
        {
            var result = new EventFlowEvaluationResult();
            if (project == null || proposal == null) return result;

            var layoutService = ServiceRegistry.Instance.Get<ISpaceLayoutService>();
            var showroomService = ServiceRegistry.Instance.Get<IShowroomService>();
            if (layoutService == null || showroomService == null || string.IsNullOrEmpty(project.SpaceId))
            {
                result.OverallFlowStatus = FlowStatus.Unknown;
                return result;
            }

            var slots = layoutService.GetBySpaceId(project.SpaceId) ?? new List<SpaceLayoutSlot>();
            var assignments = proposal.ItemSlotAssignments ?? new List<ItemSlotAssignment>();
            var itemIds = proposal.ShowroomItemIds ?? new List<string>();

            var itemsBySlot = new Dictionary<string, List<ShowroomItem>>();
            foreach (var a in assignments)
            {
                if (string.IsNullOrEmpty(a.SlotId)) continue;
                var item = showroomService.GetById(a.ShowroomItemId);
                if (item == null) continue;
                if (!itemsBySlot.ContainsKey(a.SlotId))
                    itemsBySlot[a.SlotId] = new List<ShowroomItem>();
                itemsBySlot[a.SlotId].Add(item);
            }

            int congestionRisk = 0;
            var zoneRisks = new List<string>();
            var warnings = new List<string>();

            foreach (var slot in slots)
            {
                var itemsInSlot = itemsBySlot.TryGetValue(slot.Id, out var list) ? list : new List<ShowroomItem>();
                var count = itemsInSlot.Count;
                if (count == 0) continue;

                int footprint = itemsInSlot.Sum(i => i.FootprintWeight > 0 ? i.FootprintWeight : 20);
                bool hasBlocking = itemsInSlot.Any(i => i.BlocksCirculation);
                bool hasServiceAccess = itemsInSlot.Any(i => i.RequiresServiceAccess);

                if (slot.IsCirculationCritical)
                {
                    if (count >= slot.CapacityHint && slot.CapacityHint > 0)
                    {
                        congestionRisk += slot.CongestionRiskWeight;
                        zoneRisks.Add(slot.Name + ": excesso de itens (" + count + ")");
                        warnings.Add("Zona crítica de circulação \"" + slot.Name + "\" com muitos itens; risco de gargalo.");
                    }
                    else if (hasBlocking)
                    {
                        congestionRisk += (slot.CongestionRiskWeight / 2);
                        zoneRisks.Add(slot.Name + ": itens que bloqueiam circulação");
                        warnings.Add("Itens que bloqueiam circulação em \"" + slot.Name + "\".");
                    }
                }
                else if (slot.CongestionRiskWeight > 0 && footprint > 50)
                {
                    congestionRisk += (slot.CongestionRiskWeight * System.Math.Min(100, footprint)) / 100;
                }

                if (hasServiceAccess && slot.AccessPriority < 5)
                    warnings.Add("Itens que exigem acesso de serviço em \"" + slot.Name + "\" (prioridade de acesso baixa).");
            }

            result.CongestionRiskScore = System.Math.Min(100, congestionRisk);
            result.ZoneRiskSummaries = zoneRisks;
            result.CirculationWarnings = warnings;

            int serviceOk = 0, serviceTotal = 0;
            foreach (var id in itemIds)
            {
                var item = showroomService.GetById(id);
                if (item == null || !item.RequiresServiceAccess) continue;
                serviceTotal++;
                var assignment = assignments.Find(a => a.ShowroomItemId == id);
                if (assignment != null)
                {
                    var slot = layoutService.GetById(assignment.SlotId);
                    if (slot != null && slot.AccessPriority >= item.ServiceAccessPriority)
                        serviceOk++;
                }
            }
            result.ServiceAccessScore = serviceTotal == 0 ? 100 : (int)(100.0 * serviceOk / serviceTotal);

            result.Recommendations = new List<string>();
            if (result.CongestionRiskScore > 60)
                result.Recommendations.Add("Reduzir itens em zonas críticas de circulação (entrada, área central) ou escolher itens com menor impacto.");
            if (result.ServiceAccessScore < 80 && serviceTotal > 0)
                result.Recommendations.Add("Posicionar itens que exigem acesso de serviço (buffet, palco) em slots com prioridade de acesso adequada.");
            if (result.CongestionRiskScore > 40 && result.CongestionRiskScore <= 60)
                result.Recommendations.Add("Revisar distribuição dos itens entre as zonas para equilibrar o fluxo.");

            if (result.CongestionRiskScore >= 70 || result.ServiceAccessScore < 40)
                result.OverallFlowStatus = FlowStatus.Critical;
            else if (result.CongestionRiskScore >= 40 || result.ServiceAccessScore < 70)
                result.OverallFlowStatus = FlowStatus.Warning;
            else
                result.OverallFlowStatus = FlowStatus.Good;

            return result;
        }
    }
}
