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

namespace EventsAppQuest.Infrastructure.Services
{
    /// <summary>
    /// Calcula score de aderência da proposta ao briefing (orçamento, mood, capacidade, elementos obrigatórios, riscos).
    /// </summary>
    public class MockProposalFitScoringService : IProposalFitScoringService
    {
        public ProposalFitScore CalculateScore(EventProject project, EventProjectProposal proposal)
        {
            var score = new ProposalFitScore();
            if (project == null || proposal == null) return score;

            var brief = project.ClientBrief;
            var total = proposal.TotalEstimatedPrice;
            var themeService = ServiceRegistry.Instance.Get<IVisualThemeService>();
            var showroomService = ServiceRegistry.Instance.Get<IShowroomService>();

            // BudgetFitScore (0-100)
            if (brief != null && brief.EstimatedBudgetTarget > 0)
            {
                var ratio = total / brief.EstimatedBudgetTarget;
                if (ratio >= 0.8f && ratio <= 1.2f)
                    score.BudgetFitScore = 100;
                else if (ratio <= 0.5f)
                    score.BudgetFitScore = 80;
                else if (ratio > 1.5f)
                    score.BudgetFitScore = 0;
                else if (ratio > 1.2f)
                    score.BudgetFitScore = Math.Max(0, 100 - (int)((ratio - 1.2f) * 200));
                else
                    score.BudgetFitScore = Math.Min(100, 80 + (int)((0.8f - ratio) * 50));
            }
            else
                score.BudgetFitScore = 100;

            // MoodFitScore (0-100)
            var themeMood = themeService?.GetById(proposal.ThemeId)?.Mood ?? "";
            if (brief != null && !string.IsNullOrWhiteSpace(brief.PreferredMood))
            {
                var preferred = brief.PreferredMood.Trim();
                if (!string.IsNullOrEmpty(themeMood) && themeMood.IndexOf(preferred, StringComparison.OrdinalIgnoreCase) >= 0)
                    score.MoodFitScore = 100;
                else if (string.IsNullOrEmpty(themeMood))
                    score.MoodFitScore = 50;
                else
                    score.MoodFitScore = 0;
            }
            else
                score.MoodFitScore = 100;

            // CapacityFitScore (0-100) - usa avaliação de capacidade do espaço
            var capacityService = ServiceRegistry.Instance.Get<ISpaceCapacityEvaluationService>();
            var capacityEval = capacityService?.Evaluate(project, proposal);
            if (capacityEval != null && brief != null && brief.GuestCount > 0)
            {
                switch (capacityEval.Status)
                {
                    case CapacityOperationalStatus.Comfortable: score.CapacityFitScore = 100; break;
                    case CapacityOperationalStatus.AtLimit: score.CapacityFitScore = 65; break;
                    case CapacityOperationalStatus.OverCapacity: score.CapacityFitScore = 0; break;
                    default: score.CapacityFitScore = 75; break;
                }
            }
            else
                score.CapacityFitScore = brief != null && brief.GuestCount > 0 ? 75 : 100;

            // MustHaveFitScore (0-100)
            if (brief != null && brief.MustHaveElements != null && brief.MustHaveElements.Count > 0)
            {
                var itemIds = proposal.ShowroomItemIds ?? new List<string>();
                var itemTexts = new List<string>();
                if (showroomService != null)
                    foreach (var id in itemIds)
                    {
                        var item = showroomService.GetById(id);
                        if (item != null)
                        {
                            if (!string.IsNullOrEmpty(item.Name)) itemTexts.Add(item.Name);
                            if (!string.IsNullOrEmpty(item.Description)) itemTexts.Add(item.Description);
                        }
                    }
                var combined = string.Join(" ", itemTexts);
                int matched = 0;
                foreach (var must in brief.MustHaveElements)
                {
                    if (string.IsNullOrWhiteSpace(must)) continue;
                    if (combined.IndexOf(must.Trim(), StringComparison.OrdinalIgnoreCase) >= 0)
                        matched++;
                }
                score.MustHaveFitScore = (int)Math.Round(100.0 * matched / brief.MustHaveElements.Count(e => !string.IsNullOrWhiteSpace(e)));
            }
            else
                score.MustHaveFitScore = 100;

            // RiskScore (0-100, maior = pior)
            var risk = 0;
            if (brief != null && brief.EstimatedBudgetTarget > 0 && total > brief.EstimatedBudgetTarget * 1.3f)
                risk += 40;
            if (brief != null && !string.IsNullOrWhiteSpace(brief.PreferredMood) && score.MoodFitScore < 50)
                risk += 30;
            if (brief != null && brief.MustHaveElements != null && brief.MustHaveElements.Count > 0 && score.MustHaveFitScore < 100)
                risk += 20;
            if (proposal.ReviewSummary == null || !proposal.ReviewSummary.IsReadyForPresentation)
                risk += 10;
            if (proposal.ValidationSummary?.Status == CompositionValidationStatus.Invalid)
                risk += 15;
            if (capacityEval != null && capacityEval.OverCapacity)
                risk += 25;
            var flowService = ServiceRegistry.Instance.Get<IEventFlowEvaluationService>();
            var flowEval = flowService?.Evaluate(project, proposal);
            if (flowEval != null)
            {
                if (flowEval.OverallFlowStatus == FlowStatus.Critical) risk += 25;
                else if (flowEval.OverallFlowStatus == FlowStatus.Warning) risk += 12;
                if (flowEval.CongestionRiskScore >= 70) risk += 15;
            }
            var timelineService = ServiceRegistry.Instance.Get<IEventSetupTimelineService>();
            var timelineEval = timelineService?.Evaluate(project, proposal);
            if (timelineEval != null)
            {
                if (timelineEval.ExecutionReadinessStatus == ExecutionReadinessStatus.NotReady) risk += 20;
                else if (timelineEval.ExecutionReadinessStatus == ExecutionReadinessStatus.Warning) risk += 10;
                if (timelineEval.EstimatedTotalSetupMinutes > 480) risk += 8;
            }
            var coverageService = ServiceRegistry.Instance.Get<ISupplierCoverageEvaluationService>();
            var coverageEval = coverageService?.Evaluate(project, proposal);
            if (coverageEval != null)
            {
                if (coverageEval.CoverageScore < 50) risk += 25;
                else if (coverageEval.CoverageScore < 70) risk += 12;
                if (coverageEval.MissingSupplierCapabilities != null && coverageEval.MissingSupplierCapabilities.Count > 0) risk += 15;
            }
            score.RiskScore = Math.Min(100, risk);

            // OverallScore (0-100): média dos fit scores com penalidade de risco
            var avgFit = (score.BudgetFitScore + score.MoodFitScore + score.CapacityFitScore + score.MustHaveFitScore) / 4;
            score.OverallScore = Math.Max(0, Math.Min(100, avgFit - (score.RiskScore / 2)));

            // Highlights
            score.Highlights = new List<string>();
            if (score.BudgetFitScore >= 80) score.Highlights.Add("Orçamento alinhado ao alvo");
            if (score.MoodFitScore >= 80) score.Highlights.Add("Mood alinhado ao desejado");
            if (score.CapacityFitScore >= 80 && (brief?.GuestCount ?? 0) > 0) score.Highlights.Add("Capacidade adequada ao número de convidados");
            if (score.MustHaveFitScore == 100 && (brief?.MustHaveElements?.Count ?? 0) > 0) score.Highlights.Add("Elementos obrigatórios contemplados");
            if (score.RiskScore <= 20) score.Highlights.Add("Baixo risco comercial");
            if (proposal.ReviewSummary?.IsReadyForPresentation == true) score.Highlights.Add("Pronta para apresentação");
            if (flowEval != null && flowEval.OverallFlowStatus == FlowStatus.Good && flowEval.CongestionRiskScore < 30)
                score.Highlights.Add("Fluxo e logística operacional adequados");
            if (timelineEval != null && timelineEval.ExecutionReadinessStatus == ExecutionReadinessStatus.Ready && timelineEval.DependencyIssues?.Count == 0)
                score.Highlights.Add("Cronograma de montagem viável; pronta para execução");
            if (coverageEval != null && coverageEval.CoverageScore >= 80 && (coverageEval.MissingSupplierCapabilities?.Count ?? 0) == 0)
                score.Highlights.Add("Cobertura operacional adequada pelos fornecedores");

            // Gaps
            score.Gaps = new List<string>();
            if (score.BudgetFitScore < 50) score.Gaps.Add("Orçamento acima do alvo do cliente");
            if (score.MoodFitScore < 50 && brief != null && !string.IsNullOrWhiteSpace(brief.PreferredMood)) score.Gaps.Add("Mood da proposta não alinhado ao desejado");
            if (score.CapacityFitScore < 50 && (brief?.GuestCount ?? 0) > 0) score.Gaps.Add("Proposta acima da capacidade estimada para os convidados");
            if (score.MustHaveFitScore < 100 && (brief?.MustHaveElements?.Count ?? 0) > 0) score.Gaps.Add("Elementos obrigatórios do briefing não totalmente contemplados");
            if (score.RiskScore > 50) score.Gaps.Add("Riscos comerciais identificados");
            if (flowEval != null && flowEval.CirculationWarnings != null && flowEval.CirculationWarnings.Count > 0)
                score.Gaps.Add("Fluxo: " + string.Join("; ", flowEval.CirculationWarnings));
            if (timelineEval != null && timelineEval.DependencyIssues != null && timelineEval.DependencyIssues.Count > 0)
                score.Gaps.Add("Montagem: " + string.Join("; ", timelineEval.DependencyIssues));
            if (coverageEval != null && coverageEval.MissingSupplierCapabilities != null && coverageEval.MissingSupplierCapabilities.Count > 0)
                score.Gaps.Add("Cobertura: " + string.Join("; ", coverageEval.MissingSupplierCapabilities));

            // Recommendations
            score.Recommendations = new List<string>();
            if (score.BudgetFitScore < 80 && brief != null && brief.EstimatedBudgetTarget > 0)
                score.Recommendations.Add("Ajustar itens para aproximar o orçamento ao alvo");
            if (score.MoodFitScore < 80 && brief != null && !string.IsNullOrWhiteSpace(brief.PreferredMood))
                score.Recommendations.Add("Selecionar tema que reflita o mood desejado");
            if (score.MustHaveFitScore < 100)
                score.Recommendations.Add("Incluir ou destacar elementos obrigatórios do briefing");
            if (score.CapacityFitScore < 70 && (brief?.GuestCount ?? 0) > 0)
                score.Recommendations.Add("Ajustar layout ou itens para adequar a capacidade ao número de convidados");
            if (proposal.ReviewSummary?.IsReadyForPresentation != true)
                score.Recommendations.Add("Completar narrativa e validação para prontidão de apresentação");
            if (flowEval != null && flowEval.Recommendations != null)
                foreach (var rec in flowEval.Recommendations)
                    score.Recommendations.Add(rec);
            if (timelineEval != null && timelineEval.Recommendations != null)
                foreach (var rec in timelineEval.Recommendations)
                    score.Recommendations.Add(rec);
            if (coverageEval != null && coverageEval.Recommendations != null)
                foreach (var rec in coverageEval.Recommendations)
                    score.Recommendations.Add(rec);

            return score;
        }
    }
}
