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

namespace EventsAppQuest.Presentation
{
    /// <summary>
    /// Exibe lista de propostas internas do projeto e resumo comparativo (tema, preset, valor, itens, fornecedores, prontidão).
    /// Permite duplicar proposta ativa e ativar outra proposta.
    /// </summary>
    public class ProjectProposalComparisonView : MonoBehaviour
    {
        private const string Title = "Propostas do Projeto / Comparação";
        private const string NenhumProjeto = "Nenhum projeto iniciado.";
        private const string Duplicar = "Duplicar";
        private const string Ativar = "Ativar";
        private const string Ativa = " (ativa)";
        private const string ValidText = "Válida";
        private const string WarningsText = "Avisos";
        private const string InvalidText = "Inválida";
        private const string Pronto = "Pronto";
        private const string NaoPronto = "Não pronto";

        private AppSession _session;
        private IVisualThemeService _themeService;
        private ILayoutPresetService _presetService;
        private IProposalFitScoringService _scoringService;
        private ISpaceCapacityEvaluationService _capacityService;
        private IEventFlowEvaluationService _flowService;
        private IEventSetupTimelineService _timelineService;
        private ISupplierCoverageEvaluationService _coverageService;
        private ICommercialPackageService _packageService;
        private IEventMomentPlanningService _momentPlanningService;
        private IEventMomentTransitionService _transitionService;
        private IProposalGuidedTourService _guidedTourService;
        private IProposalVisualHotspotService _hotspotService;
        private IProposalSceneStateService _sceneStateService;
        private IMRPresentationPlanningService _mrPlanningService;
        private Transform _listRoot;
        private Transform _compareRoot;
        private Font _font;

        private void Start()
        {
            _session = ServiceRegistry.Instance.Get<AppSession>();
            _themeService = ServiceRegistry.Instance.Get<IVisualThemeService>();
            _presetService = ServiceRegistry.Instance.Get<ILayoutPresetService>();
            _scoringService = ServiceRegistry.Instance.Get<IProposalFitScoringService>();
            _capacityService = ServiceRegistry.Instance.Get<ISpaceCapacityEvaluationService>();
            _flowService = ServiceRegistry.Instance.Get<IEventFlowEvaluationService>();
            _timelineService = ServiceRegistry.Instance.Get<IEventSetupTimelineService>();
            _coverageService = ServiceRegistry.Instance.Get<ISupplierCoverageEvaluationService>();
            _packageService = ServiceRegistry.Instance.Get<ICommercialPackageService>();
            _momentPlanningService = ServiceRegistry.Instance.Get<IEventMomentPlanningService>();
            _transitionService = ServiceRegistry.Instance.Get<IEventMomentTransitionService>();
            _guidedTourService = ServiceRegistry.Instance.Get<IProposalGuidedTourService>();
            _hotspotService = ServiceRegistry.Instance.Get<IProposalVisualHotspotService>();
            _sceneStateService = ServiceRegistry.Instance.Get<IProposalSceneStateService>();
            _mrPlanningService = ServiceRegistry.Instance.Get<IMRPresentationPlanningService>();
            if (_session != null)
                _session.OnSessionChanged += UpdateContent;

            _font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
            BuildUI();
            UpdateContent();
        }

        private void OnDestroy()
        {
            if (_session != null)
                _session.OnSessionChanged -= UpdateContent;
        }

        private void BuildUI()
        {
            var layout = gameObject.GetComponent<VerticalLayoutGroup>();
            if (layout == null)
            {
                layout = gameObject.AddComponent<VerticalLayoutGroup>();
                layout.spacing = 8;
                layout.padding = new RectOffset(12, 12, 12, 12);
                layout.childForceExpandHeight = false;
                layout.childForceExpandWidth = true;
            }

            var titleGo = new GameObject("Title");
            titleGo.transform.SetParent(transform, false);
            titleGo.AddComponent<RectTransform>().sizeDelta = new Vector2(0, 22);
            var titleText = titleGo.AddComponent<Text>();
            titleText.text = Title;
            titleText.font = _font;
            titleText.fontSize = 16;
            titleText.fontStyle = FontStyle.Bold;

            var btnRow = new GameObject("ButtonRow");
            btnRow.transform.SetParent(transform, false);
            btnRow.AddComponent<RectTransform>().sizeDelta = new Vector2(0, 28);
            var btnHlg = btnRow.AddComponent<HorizontalLayoutGroup>();
            btnHlg.spacing = 8;
            btnHlg.childForceExpandWidth = false;
            CreateButton(btnRow.transform, Duplicar + " proposta ativa", () => _session?.DuplicateActiveProposal());

            _listRoot = new GameObject("ProposalsListRoot").transform;
            _listRoot.SetParent(transform, false);
            _listRoot.gameObject.AddComponent<LayoutElement>().preferredHeight = 140;
            var listVlg = _listRoot.gameObject.AddComponent<VerticalLayoutGroup>();
            listVlg.spacing = 4;
            listVlg.childForceExpandHeight = false;
            listVlg.childForceExpandWidth = true;

            var compareLabel = new GameObject("CompareLabel");
            compareLabel.transform.SetParent(transform, false);
            compareLabel.AddComponent<RectTransform>().sizeDelta = new Vector2(0, 18);
            var compareLabelText = compareLabel.AddComponent<Text>();
            compareLabelText.text = "Resumo comparativo";
            compareLabelText.font = _font;
            compareLabelText.fontSize = 13;
            compareLabelText.fontStyle = FontStyle.Bold;

            _compareRoot = new GameObject("CompareRoot").transform;
            _compareRoot.SetParent(transform, false);
            _compareRoot.gameObject.AddComponent<LayoutElement>().preferredHeight = 200;
            var compareVlg = _compareRoot.gameObject.AddComponent<VerticalLayoutGroup>();
            compareVlg.spacing = 2;
            compareVlg.childForceExpandHeight = false;
            compareVlg.childForceExpandWidth = true;
        }

        private void CreateButton(Transform parent, string label, System.Action onClick)
        {
            var go = new GameObject("Btn");
            go.transform.SetParent(parent, false);
            go.AddComponent<RectTransform>().sizeDelta = new Vector2(180, 26);
            var le = go.AddComponent<LayoutElement>();
            le.preferredWidth = 180;
            le.preferredHeight = 26;
            var btn = go.AddComponent<Button>();
            go.AddComponent<Image>().color = new Color(0.35f, 0.5f, 0.65f, 1f);
            var textGo = new GameObject("Text");
            textGo.transform.SetParent(go.transform, false);
            var textRt = textGo.AddComponent<RectTransform>();
            textRt.anchorMin = Vector2.zero;
            textRt.anchorMax = Vector2.one;
            textRt.offsetMin = Vector2.zero;
            textRt.offsetMax = Vector2.zero;
            var text = textGo.AddComponent<Text>();
            text.text = label;
            text.font = _font;
            text.fontSize = 12;
            text.alignment = TextAnchor.MiddleCenter;
            text.color = Color.white;
            btn.onClick.AddListener(() => onClick?.Invoke());
        }

        private void UpdateContent()
        {
            ClearChildren(_listRoot);
            ClearChildren(_compareRoot);

            var project = _session?.CurrentProject;
            if (project == null)
            {
                AppendText(_listRoot, NenhumProjeto);
                return;
            }

            var proposals = project.Proposals ?? new List<EventProjectProposal>();
            var activeId = project.ActiveProposalId;

            foreach (var p in proposals)
            {
                var isActive = p.Id == activeId;
                var line = new GameObject("ProposalLine");
                line.transform.SetParent(_listRoot, false);
                line.AddComponent<RectTransform>().sizeDelta = new Vector2(0, 24);
                var rowHlg = line.AddComponent<HorizontalLayoutGroup>();
                rowHlg.spacing = 8;
                rowHlg.childForceExpandWidth = false;
                rowHlg.childForceExpandHeight = true;

                var nameLabel = new GameObject("Name");
                nameLabel.transform.SetParent(line.transform, false);
                var nameLe = nameLabel.AddComponent<LayoutElement>();
                nameLe.flexibleWidth = 1;
                nameLe.preferredWidth = 200;
                var nameText = nameLabel.AddComponent<Text>();
                nameText.text = (p.Name ?? "Proposta") + (isActive ? Ativa : "");
                nameText.font = _font;
                nameText.fontSize = 12;
                nameText.fontStyle = isActive ? FontStyle.Bold : FontStyle.Normal;

                if (!isActive)
                {
                    var activateBtn = new GameObject("ActivateBtn");
                    activateBtn.transform.SetParent(line.transform, false);
                    activateBtn.AddComponent<LayoutElement>().preferredWidth = 70;
                    var ab = activateBtn.AddComponent<Button>();
                    activateBtn.AddComponent<Image>().color = new Color(0.3f, 0.55f, 0.35f, 1f);
                    var abTextGo = new GameObject("Text");
                    abTextGo.transform.SetParent(activateBtn.transform, false);
                    var abRt = abTextGo.AddComponent<RectTransform>();
                    abRt.anchorMin = Vector2.zero;
                    abRt.anchorMax = Vector2.one;
                    abRt.offsetMin = Vector2.zero;
                    abRt.offsetMax = Vector2.zero;
                    var abText = abTextGo.AddComponent<Text>();
                    abText.text = Ativar;
                    abText.font = _font;
                    abText.fontSize = 11;
                    abText.alignment = TextAnchor.MiddleCenter;
                    abText.color = Color.white;
                    var proposalId = p.Id;
                    ab.onClick.AddListener(() => _session?.ActivateProposal(proposalId));
                }
            }

            if (proposals.Count == 0)
                AppendText(_listRoot, "Nenhuma proposta. Inicie o projeto para criar a proposta inicial.");

            var brief = project.ClientBrief;
            // Garantir FitScore em cada proposta para comparação
            if (_scoringService != null)
            {
                foreach (var p in proposals)
                {
                    if (p.FitScore == null)
                        p.FitScore = _scoringService.CalculateScore(project, p);
                }
            }
            // Melhor orçamento, mood, acomodação, fluxo, execução, cobertura, encaixe comercial, jornada, transições, roteiro guiado, Quest/MR
            string bestBudgetName = null, bestMoodName = null, bestCapacityName = null, bestFlowName = null, bestSetupName = null, bestCoverageName = null, bestCommercialFitName = null, bestJourneyName = null, bestSmoothnessName = null, leastReconfigName = null, leastFrictionName = null, bestGuidedName = null, bestVisualImpactName = null, bestUpsellVisualName = null, bestSceneStateName = null, bestSceneContinuityName = null, bestQuestReadyName = null, bestImmersiveClosingName = null;
            int bestBudget = -1, bestMood = -1, bestCapacity = -1;
            int bestJourneyWithContent = -1;
            int bestSmoothness = -1;
            int leastReconfigCount = int.MaxValue;
            int leastFrictionCount = int.MaxValue;
            int bestGuidedSteps = -1;
            int bestHotspotCount = -1;
            int bestPremiumHotspotCount = -1;
            int bestSceneStateCount = -1;
            int bestSceneContinuityScore = -1;
            int bestFlowCongestion = 101;
            int bestReadinessValue = 99;
            int bestSetupMinutes = int.MaxValue;
            int bestCoverageScore = -1;
            int bestCoverageGaps = int.MaxValue;
            float bestCommercialFitDev = float.MaxValue;
            foreach (var p in proposals)
            {
                if (p.FitScore != null)
                {
                    if (p.FitScore.BudgetFitScore > bestBudget) { bestBudget = p.FitScore.BudgetFitScore; bestBudgetName = p.Name ?? "Proposta"; }
                    if (p.FitScore.MoodFitScore > bestMood) { bestMood = p.FitScore.MoodFitScore; bestMoodName = p.Name ?? "Proposta"; }
                    if (p.FitScore.CapacityFitScore > bestCapacity) { bestCapacity = p.FitScore.CapacityFitScore; bestCapacityName = p.Name ?? "Proposta"; }
                }
                if (_flowService != null)
                {
                    var flow = _flowService.Evaluate(project, p);
                    if (flow.CongestionRiskScore < bestFlowCongestion)
                    {
                        bestFlowCongestion = flow.CongestionRiskScore;
                        bestFlowName = p.Name ?? "Proposta";
                    }
                }
                if (_timelineService != null)
                {
                    var setup = _timelineService.Evaluate(project, p);
                    var statusVal = (int)setup.ExecutionReadinessStatus;
                    var better = statusVal < bestReadinessValue
                        || (statusVal == bestReadinessValue && setup.EstimatedTotalSetupMinutes < bestSetupMinutes);
                    if (better)
                    {
                        bestReadinessValue = statusVal;
                        bestSetupMinutes = setup.EstimatedTotalSetupMinutes;
                        bestSetupName = p.Name ?? "Proposta";
                    }
                }
                if (_coverageService != null)
                {
                    var cov = _coverageService.Evaluate(project, p);
                    var gaps = cov.MissingSupplierCapabilities?.Count ?? 0;
                    var better = cov.CoverageScore > bestCoverageScore
                        || (cov.CoverageScore == bestCoverageScore && gaps < bestCoverageGaps);
                    if (better)
                    {
                        bestCoverageScore = cov.CoverageScore;
                        bestCoverageGaps = gaps;
                        bestCoverageName = p.Name ?? "Proposta";
                    }
                }
                if (_packageService != null && !string.IsNullOrEmpty(p.SelectedCommercialPackageId))
                {
                    var pkg = _packageService.GetById(p.SelectedCommercialPackageId);
                    if (pkg != null && pkg.TargetBudgetRangeMin > 0)
                    {
                        var mid = (pkg.TargetBudgetRangeMin + pkg.TargetBudgetRangeMax) / 2f;
                        var dev = System.Math.Abs(p.TotalEstimatedPrice - mid);
                        if (dev < bestCommercialFitDev)
                        {
                            bestCommercialFitDev = dev;
                            bestCommercialFitName = p.Name ?? "Proposta";
                        }
                    }
                }
                if (_momentPlanningService != null)
                {
                    var plans = p.MomentPlans != null && p.MomentPlans.Count > 0
                        ? p.MomentPlans
                        : _momentPlanningService.GenerateMomentPlan(project, p);
                    var withContent = plans?.Count(pl => (pl.RelatedShowroomItemIds?.Count ?? 0) > 0 || (pl.KeySupplierIds?.Count ?? 0) > 0) ?? 0;
                    if (withContent > bestJourneyWithContent)
                    {
                        bestJourneyWithContent = withContent;
                        bestJourneyName = p.Name ?? "Proposta";
                    }
                }
                if (_transitionService != null)
                {
                    if (p.MomentPlans == null || p.MomentPlans.Count < 2)
                    {
                        var plans = _momentPlanningService?.GenerateMomentPlan(project, p);
                        if (plans != null) p.MomentPlans = new List<ProposalMomentPlan>(plans);
                    }
                    var trans = p.MomentTransitions != null && p.MomentTransitions.Count > 0
                        ? p.MomentTransitions
                        : _transitionService.GenerateTransitions(project, p);
                    if (trans != null && trans.Count > 0)
                    {
                        var avg = 0;
                        foreach (var t in trans) avg += t.SmoothnessScore;
                        avg = avg / trans.Count;
                        if (avg > bestSmoothness) { bestSmoothness = avg; bestSmoothnessName = p.Name ?? "Proposta"; }
                        var reconfigCount = trans.Count(t => t.RequiresSpaceReset);
                        if (reconfigCount < leastReconfigCount) { leastReconfigCount = reconfigCount; leastReconfigName = p.Name ?? "Proposta"; }
                        var frictionCount = trans.Count(t => t.RequiresSupplierCoordination);
                        if (frictionCount < leastFrictionCount) { leastFrictionCount = frictionCount; leastFrictionName = p.Name ?? "Proposta"; }
                    }
                }
                if (_guidedTourService != null)
                {
                    var tourSteps = p.GuidedTourSteps != null && p.GuidedTourSteps.Count > 0
                        ? p.GuidedTourSteps
                        : _guidedTourService.GenerateGuidedTour(project, p);
                    var count = tourSteps?.Count ?? 0;
                    if (count > bestGuidedSteps) { bestGuidedSteps = count; bestGuidedName = p.Name ?? "Proposta"; }
                    if (tourSteps != null && count > 0 && (p.GuidedTourSteps == null || p.GuidedTourSteps.Count == 0))
                        p.GuidedTourSteps = new List<ProposalGuidedTourStep>(tourSteps);
                }
                if (_hotspotService != null)
                {
                    var hotspots = p.VisualHotspots != null && p.VisualHotspots.Count > 0
                        ? p.VisualHotspots
                        : _hotspotService.GenerateHotspots(project, p);
                    var hCount = hotspots?.Count ?? 0;
                    if (hCount > bestHotspotCount) { bestHotspotCount = hCount; bestVisualImpactName = p.Name ?? "Proposta"; }
                    if (hotspots != null)
                    {
                        var premiumCount = hotspots.Count(h => h.IsPremiumUpsell);
                        if (premiumCount > bestPremiumHotspotCount) { bestPremiumHotspotCount = premiumCount; bestUpsellVisualName = p.Name ?? "Proposta"; }
                        if (hCount > 0 && (p.VisualHotspots == null || p.VisualHotspots.Count == 0))
                            p.VisualHotspots = new List<ProposalVisualHotspot>(hotspots);
                    }
                }
                if (_sceneStateService != null)
                {
                    var states = p.SceneStates != null && p.SceneStates.Count > 0 ? p.SceneStates : _sceneStateService.GenerateSceneStates(project, p);
                    if (states != null && states.Count > 0)
                    {
                        if (p.SceneStates == null || p.SceneStates.Count == 0)
                            p.SceneStates = new List<ProposalSceneState>(states);
                        if (states.Count > bestSceneStateCount) { bestSceneStateCount = states.Count; bestSceneStateName = p.Name ?? "Proposta"; }
                        var withTransition = states.Count(s => !string.IsNullOrEmpty(s.TransitionFromPreviousSummary));
                        if (withTransition > bestSceneContinuityScore) { bestSceneContinuityScore = withTransition; bestSceneContinuityName = p.Name ?? "Proposta"; }
                    }
                }
                if (_mrPlanningService != null)
                {
                    var mrPlan = p.MRPresentationPlan ?? _mrPlanningService.GeneratePlan(project, p);
                    if (mrPlan != null)
                    {
                        if (p.MRPresentationPlan == null) p.MRPresentationPlan = mrPlan;
                        if (mrPlan.ReadyForMRMapping && bestQuestReadyName == null) bestQuestReadyName = p.Name ?? "Proposta";
                        if (mrPlan.TargetExperienceMode == MRPresentationTargetMode.ExecutiveClosingMode && mrPlan.ReadyForMRMapping)
                            bestImmersiveClosingName = p.Name ?? "Proposta";
                    }
                }
            }
            if (project?.LastDecisionSummary?.DecisionReadinessLevel == ProposalDecisionReadinessLevel.ReadyToClose && !string.IsNullOrEmpty(project.LastRecommendationSummary?.RecommendedProposalId) && bestImmersiveClosingName == null)
            {
                var recName = project.Proposals?.FirstOrDefault(pr => pr.Id == project.LastRecommendationSummary.RecommendedProposalId)?.Name;
                if (!string.IsNullOrEmpty(recName)) bestImmersiveClosingName = recName;
            }
            if (bestBudgetName != null || bestMoodName != null || bestCapacityName != null || bestFlowName != null || bestSetupName != null || bestCoverageName != null || bestCommercialFitName != null || bestJourneyName != null || bestSmoothnessName != null || leastReconfigName != null || leastFrictionName != null || bestGuidedName != null || bestVisualImpactName != null || bestUpsellVisualName != null || bestSceneStateName != null || bestSceneContinuityName != null || bestQuestReadyName != null || bestImmersiveClosingName != null)
            {
                var sumLine = new GameObject("SummaryScores");
                sumLine.transform.SetParent(_compareRoot, false);
                sumLine.AddComponent<RectTransform>().sizeDelta = new Vector2(0, 14);
                var sumText = sumLine.AddComponent<Text>();
                var parts = new System.Collections.Generic.List<string>();
                if (bestBudgetName != null) parts.Add("Melhor orçamento: " + bestBudgetName);
                if (bestMoodName != null) parts.Add("Melhor mood: " + bestMoodName);
                if (bestCapacityName != null) parts.Add("Melhor acomodação: " + bestCapacityName);
                if (bestFlowName != null) parts.Add("Melhor fluxo: " + bestFlowName);
                if (bestSetupName != null) parts.Add("Mais pronta para execução: " + bestSetupName);
                if (bestCoverageName != null) parts.Add("Melhor cobertura: " + bestCoverageName);
                if (bestCommercialFitName != null) parts.Add("Melhor encaixe comercial: " + bestCommercialFitName);
                if (bestJourneyName != null) parts.Add("Jornada mais completa: " + bestJourneyName);
                if (bestSmoothnessName != null) parts.Add("Jornada mais fluida: " + bestSmoothnessName);
                if (leastReconfigName != null) parts.Add("Menos reconfig.: " + leastReconfigName);
                if (leastFrictionName != null) parts.Add("Menor atrito oper.: " + leastFrictionName);
                if (bestGuidedName != null) parts.Add("Apresentação mais forte: " + bestGuidedName + " | Roteiro mais claro: " + bestGuidedName);
                if (bestVisualImpactName != null) parts.Add("Maior impacto visual: " + bestVisualImpactName);
                if (bestUpsellVisualName != null) parts.Add("Melhor upsell visual: " + bestUpsellVisualName);
                if (bestSceneStateName != null) parts.Add("Evolução visual mais rica: " + bestSceneStateName);
                if (bestSceneContinuityName != null) parts.Add("Estados mais coerentes / melhor continuidade visual: " + bestSceneContinuityName);
                if (bestQuestReadyName != null) parts.Add("Mais pronta p/ Quest: " + bestQuestReadyName);
                if (bestGuidedName != null) parts.Add("Melhor potencial de tour guiado: " + bestGuidedName);
                if (bestImmersiveClosingName != null) parts.Add("Melhor fechamento imersivo: " + bestImmersiveClosingName);
                var temporal = project.LastTemporalComparison;
                if (temporal != null)
                {
                    var baseName = project.Proposals?.FirstOrDefault(p => p.Id == temporal.BaseProposalId)?.Name ?? "Base";
                    var compName = project.Proposals?.FirstOrDefault(p => p.Id == temporal.ComparedProposalId)?.Name ?? "Comparada";
                    var stronger = temporal.StrongerMoments?.Count ?? 0;
                    var weaker = temporal.WeakerMoments?.Count ?? 0;
                    var betterEvolution = stronger > weaker ? baseName : (weaker > stronger ? compName : null);
                    if (!string.IsNullOrEmpty(betterEvolution)) parts.Add("Melhor evolução da experiência: " + betterEvolution);
                    var bestVisualName = ResolveProposalNameForId(project, temporal.BetterVisualContinuity);
                    if (!string.IsNullOrEmpty(bestVisualName)) parts.Add("Melhor jornada visual: " + bestVisualName);
                    var bestOpName = ResolveProposalNameForId(project, temporal.BetterOperationalContinuity);
                    if (!string.IsNullOrEmpty(bestOpName)) parts.Add("Melhor continuidade operacional: " + bestOpName);
                    var bestSalesName = ResolveProposalNameForId(project, temporal.BetterSalesImpact);
                    if (!string.IsNullOrEmpty(bestSalesName)) parts.Add("Melhor impacto comercial: " + bestSalesName);
                }
                sumText.text = string.Join(" | ", parts);
                sumText.font = _font;
                sumText.fontSize = 10;
            }
            // Resumo comparativo: uma linha por proposta com tema, preset, valor, itens, forn., prontidão, score, orçamento vs alvo, tema vs mood
            foreach (var p in proposals)
            {
                var themeName = ResolveThemeName(p.ThemeId);
                var themeMood = ResolveThemeMood(p.ThemeId);
                var presetName = ResolvePresetName(p.PresetId);
                var validationStatus = p.ValidationSummary?.Status ?? CompositionValidationStatus.Valid;
                var ready = p.ReviewSummary != null && p.ReviewSummary.IsReadyForPresentation;
                var scoreStr = p.FitScore != null ? $" | Score: {p.FitScore.OverallScore}" : "";
                var capStr = "";
                if (_capacityService != null && brief != null && brief.GuestCount > 0)
                {
                    var cap = _capacityService.Evaluate(project, p);
                    capStr = $" | Cap: {cap.EstimatedCapacityMin}–{cap.EstimatedCapacityMax}";
                    if (cap.GuestCountFromBrief > 0)
                    {
                        var diff = cap.EstimatedCapacityMax - cap.GuestCountFromBrief;
                        if (diff < 0) capStr += " (" + diff + " conv)";
                        else if (cap.FitsComfortably) capStr += " ✓";
                    }
                }
                var budgetInfo = "";
                if (brief != null && brief.EstimatedBudgetTarget > 0)
                {
                    var diff = p.TotalEstimatedPrice - brief.EstimatedBudgetTarget;
                    var ratio = p.TotalEstimatedPrice / brief.EstimatedBudgetTarget;
                    if (ratio >= 0.8f && ratio <= 1.2f)
                        budgetInfo = " | Orçamento: dentro do alvo";
                    else if (diff > 0)
                        budgetInfo = $" | R$ {diff:N0} acima do alvo";
                    else
                        budgetInfo = $" | R$ {-diff:N0} abaixo do alvo";
                }
                var moodInfo = "";
                if (brief != null && !string.IsNullOrWhiteSpace(brief.PreferredMood))
                {
                    var desired = brief.PreferredMood.Trim();
                    if (!string.IsNullOrEmpty(themeMood) && themeMood.IndexOf(desired, System.StringComparison.OrdinalIgnoreCase) >= 0)
                        moodInfo = " | Tema alinhado ao mood desejado";
                    else
                        moodInfo = $" | Tema: {themeName} | Mood desejado: {desired}";
                }
                var flowStr = "";
                if (_flowService != null)
                {
                    var flow = _flowService.Evaluate(project, p);
                    flowStr = " | Fluxo: risco " + flow.CongestionRiskScore + " | acesso " + flow.ServiceAccessScore;
                }
                var setupStr = "";
                if (_timelineService != null)
                {
                    var setup = _timelineService.Evaluate(project, p);
                    var min = setup.EstimatedTotalSetupMinutes;
                    setupStr = " | Montagem: " + min + " min | " + (setup.ExecutionReadinessStatus == ExecutionReadinessStatus.Ready ? "pronta" : setup.ExecutionReadinessStatus == ExecutionReadinessStatus.Warning ? "atenção" : "não pronta");
                }
                var coverageStr = "";
                if (_coverageService != null)
                {
                    var cov = _coverageService.Evaluate(project, p);
                    var gaps = cov.MissingSupplierCapabilities?.Count ?? 0;
                    coverageStr = " | Cobertura: " + cov.CoverageScore + (gaps > 0 ? " (" + gaps + " lacunas)" : "");
                }
                var packageStr = "";
                if (_packageService != null && !string.IsNullOrEmpty(p.SelectedCommercialPackageId))
                {
                    var pkg = _packageService.GetById(p.SelectedCommercialPackageId);
                    packageStr = pkg != null ? " | Pacote: " + pkg.Name + " (" + pkg.Tier + ")" : " | Pacote: —";
                }
                var journeyStr = "";
                if (_momentPlanningService != null)
                {
                    var plans = p.MomentPlans != null && p.MomentPlans.Count > 0
                        ? p.MomentPlans
                        : _momentPlanningService.GenerateMomentPlan(project, p);
                    var totalPhases = plans?.Count ?? 0;
                    var withContent = plans?.Count(pl => (pl.RelatedShowroomItemIds?.Count ?? 0) > 0 || (pl.KeySupplierIds?.Count ?? 0) > 0) ?? 0;
                    journeyStr = " | Jornada: " + totalPhases + " fases (" + withContent + " c/ conteúdo)";
                }
                var guidedStr = "";
                if (_guidedTourService != null)
                {
                    var tourSteps = p.GuidedTourSteps != null && p.GuidedTourSteps.Count > 0 ? p.GuidedTourSteps : _guidedTourService.GenerateGuidedTour(project, p);
                    var tourCount = tourSteps?.Count ?? 0;
                    if (tourCount > 0)
                    {
                        guidedStr = " | Roteiro: " + tourCount + " passos";
                        if (p.ReviewSummary != null && p.ReviewSummary.ReadyForGuidedPresentation)
                            guidedStr += " (pronta p/ guiada)";
                    }
                }
                var hotspotStr = "";
                if (_hotspotService != null)
                {
                    var hotspots = p.VisualHotspots != null && p.VisualHotspots.Count > 0 ? p.VisualHotspots : _hotspotService.GenerateHotspots(project, p);
                    var hCount = hotspots?.Count ?? 0;
                    if (hCount > 0)
                    {
                        hotspotStr = " | Hotspots: " + hCount;
                        var premiumCount = hotspots?.Count(h => h.IsPremiumUpsell) ?? 0;
                        if (premiumCount > 0) hotspotStr += " (" + premiumCount + " premium)";
                    }
                }
                var transitionStr = "";
                if (_transitionService != null)
                {
                    if (p.MomentTransitions == null || p.MomentTransitions.Count == 0)
                    {
                        var trans = _transitionService.GenerateTransitions(project, p);
                        if (trans != null) p.MomentTransitions = new List<EventMomentTransition>(trans);
                    }
                    var transList = p.MomentTransitions ?? new List<EventMomentTransition>();
                    if (transList.Count > 0)
                    {
                        var avg = 0;
                        foreach (var t in transList) avg += t.SmoothnessScore;
                        avg = avg / transList.Count;
                        transitionStr = " | Trans.: " + transList.Count + " (fluidez " + avg + ")";
                    }
                }
                var sceneStateStr = "";
                if (_sceneStateService != null)
                {
                    var states = p.SceneStates != null && p.SceneStates.Count > 0 ? p.SceneStates : _sceneStateService.GenerateSceneStates(project, p);
                    if (states != null && states.Count > 0)
                    {
                        if (p.SceneStates == null || p.SceneStates.Count == 0)
                            p.SceneStates = new List<ProposalSceneState>(states);
                        sceneStateStr = " | Estados cena: " + states.Count;
                    }
                }
                var mrPlanStr = "";
                if (_mrPlanningService != null)
                {
                    var mrPlan = p.MRPresentationPlan ?? _mrPlanningService.GeneratePlan(project, p);
                    if (mrPlan != null)
                    {
                        if (p.MRPresentationPlan == null) p.MRPresentationPlan = mrPlan;
                        mrPlanStr = " | Plano Quest: Sim | Pronto MR: " + (mrPlan.ReadyForMRMapping ? "Sim" : "Não");
                    }
                    else
                        mrPlanStr = " | Plano Quest: Não";
                }
                var line = new GameObject("CompareRow");
                line.transform.SetParent(_compareRoot, false);
                line.AddComponent<RectTransform>().sizeDelta = new Vector2(0, 16);
                var t = line.AddComponent<Text>();
                t.text = $"{p.Name ?? "Proposta"} — Tema: {themeName} | Preset: {presetName} | R$ {p.TotalEstimatedPrice:N0} | {p.ShowroomItemIds?.Count ?? 0} itens | {p.SupplierCount} forn. | {ValidationStatusText(validationStatus)} | {(ready ? Pronto : NaoPronto)}{scoreStr}{capStr}{budgetInfo}{moodInfo}{flowStr}{setupStr}{coverageStr}{packageStr}{journeyStr}{transitionStr}{guidedStr}{hotspotStr}{sceneStateStr}{mrPlanStr}";
                t.font = _font;
                t.fontSize = 11;
                t.fontStyle = p.Id == activeId ? FontStyle.Bold : FontStyle.Normal;
            }
        }

        private string ResolveThemeMood(string themeId)
        {
            if (string.IsNullOrEmpty(themeId)) return "";
            var theme = _themeService?.GetById(themeId);
            return theme?.Mood ?? "";
        }

        private string ResolveThemeName(string themeId)
        {
            if (string.IsNullOrEmpty(themeId)) return "—";
            var theme = _themeService?.GetById(themeId);
            return theme?.Name ?? themeId;
        }

        private string ResolvePresetName(string presetId)
        {
            if (string.IsNullOrEmpty(presetId)) return "—";
            var preset = _presetService?.GetById(presetId);
            return preset?.Name ?? presetId;
        }

        private static string ResolveProposalNameForId(EventProject project, string proposalId)
        {
            if (string.IsNullOrEmpty(proposalId) || project?.Proposals == null) return null;
            var p = project.Proposals.FirstOrDefault(x => x.Id == proposalId);
            return p?.Name;
        }

        private static string ValidationStatusText(CompositionValidationStatus s)
        {
            switch (s)
            {
                case CompositionValidationStatus.Valid: return ValidText;
                case CompositionValidationStatus.HasWarnings: return WarningsText;
                case CompositionValidationStatus.Invalid: return InvalidText;
                default: return "—";
            }
        }

        private void AppendText(Transform parent, string text)
        {
            var go = new GameObject("TextLine");
            go.transform.SetParent(parent, false);
            go.AddComponent<RectTransform>().sizeDelta = new Vector2(0, 16);
            var t = go.AddComponent<Text>();
            t.text = text;
            t.font = _font;
            t.fontSize = 12;
        }

        private static void ClearChildren(Transform root)
        {
            if (root == null) return;
            for (var i = root.childCount - 1; i >= 0; i--)
                Object.Destroy(root.GetChild(i).gameObject);
        }
    }
}
