using Microsoft.UI;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using System.Collections.ObjectModel;
using TornadoAce_CJOnStyle.Domain;
using TornadoAce_CJOnStyle.Services;
using Windows.UI;

namespace TornadoAce_CJOnStyle.ViewModels
{
    public partial class MainViewModel : BaseViewModel
    {
        private readonly AutomationWorkspace workspace;
        private readonly PocAutomationEngine automationEngine;
        private readonly PocRunLogWriter pocRunLogWriter = new();
        private int selectedCueSheetIndex;
        private CueSheetRecord activeCueSheet = null!;
        private ErpScheduleRecord? activeSchedule;
        private SceneDataSnapshot activeScene = null!;

        public MainViewModel()
        {
            Title = "CG 제작 자동화";
            workspace = AutomationWorkspace.CreateDemo();
            automationEngine = new PocAutomationEngine(workspace);
            var initialSelection = automationEngine.SelectCueSheet(selectedCueSheetIndex);
            var initialInspectionSummary = automationEngine.InspectWorkspace(workspace.ActiveTemplate);
            activeCueSheet = initialSelection.Record;
            activeSchedule = automationEngine.FindSchedule(activeCueSheet);
            activeScene = automationEngine.GenerateScene(activeCueSheet, workspace.ActiveTemplate);

            BuildPhase = "INITIAL BUILD";
            OperatorMessage = "큐시트 플랫폼, Tornado Scene 템플릿, 자동 검수 결과를 한 화면에서 확인하는 운영 콘솔 초안입니다.";
            LastCueSheetSyncText = FormatCueSheetSelection(initialSelection);
            ActiveTemplateName = workspace.ActiveTemplate.TemplateName;
            InspectionSummary = FormatInspectionSummary(initialInspectionSummary);
            SceneSnapshotLabel = $"{activeScene.SceneName} / visible text objects";
            SceneSnapshotText = activeScene.ToPreviewJson();
            LoginOperatorName = "producer";
            LaunchMessage = "TornadoAce";
            LlmPolicyText = "사내 LLM 우선, 외부 서비스는 정책 승인 후";
            LlmPolicyDetail = "1차 Text Diffing 실패 건만 2차 LLM 판정으로 이동하고, 가격·구성·방송시간 변경은 높은 중요도로 표시합니다.";
            PocRunLogText = "PoC 로그 대기";

            LoadStatusCards();
            LoadPipelineSteps();
            LoadFieldMappings();
            LoadMappingValidation();
            LoadEndpoints();
            LoadTornadoAdapterChecks();
            LoadRequirementCoverage();
            LoadScheduleMatches();
            LoadInspectionQueue(initialInspectionSummary.Results);
            LoadInspectionDetails(initialInspectionSummary.Results);
            LoadLlmReviewRequests(initialInspectionSummary.Results);
        }

        private string buildPhase = string.Empty;
        private string operatorMessage = string.Empty;
        private string lastCueSheetSyncText = string.Empty;
        private string activeTemplateName = string.Empty;
        private string inspectionSummary = string.Empty;
        private string sceneSnapshotLabel = string.Empty;
        private string sceneSnapshotText = string.Empty;
        private string llmPolicyText = string.Empty;
        private string llmPolicyDetail = string.Empty;
        private string pocRunLogText = string.Empty;
        private string loginOperatorName = string.Empty;
        private string launchMessage = string.Empty;
        private Visibility loginScreenVisibility = Visibility.Visible;
        private Visibility launchScreenVisibility = Visibility.Collapsed;
        private Visibility mainShellVisibility = Visibility.Collapsed;

        public string BuildPhase
        {
            get => buildPhase;
            set => SetProperty(ref buildPhase, value);
        }

        public string OperatorMessage
        {
            get => operatorMessage;
            set => SetProperty(ref operatorMessage, value);
        }

        public string LastCueSheetSyncText
        {
            get => lastCueSheetSyncText;
            set => SetProperty(ref lastCueSheetSyncText, value);
        }

        public string ActiveTemplateName
        {
            get => activeTemplateName;
            set => SetProperty(ref activeTemplateName, value);
        }

        public string InspectionSummary
        {
            get => inspectionSummary;
            set => SetProperty(ref inspectionSummary, value);
        }

        public string SceneSnapshotLabel
        {
            get => sceneSnapshotLabel;
            set => SetProperty(ref sceneSnapshotLabel, value);
        }

        public string SceneSnapshotText
        {
            get => sceneSnapshotText;
            set => SetProperty(ref sceneSnapshotText, value);
        }

        public string LlmPolicyText
        {
            get => llmPolicyText;
            set => SetProperty(ref llmPolicyText, value);
        }

        public string LlmPolicyDetail
        {
            get => llmPolicyDetail;
            set => SetProperty(ref llmPolicyDetail, value);
        }

        public string PocRunLogText
        {
            get => pocRunLogText;
            set => SetProperty(ref pocRunLogText, value);
        }

        public ObservableCollection<StatusCardViewModel> StatusCards { get; } = [];

        public ObservableCollection<PipelineStepViewModel> PipelineSteps { get; } = [];

        public ObservableCollection<FieldMappingViewModel> FieldMappings { get; } = [];

        public ObservableCollection<MappingValidationViewModel> MappingValidations { get; } = [];

        public ObservableCollection<IntegrationEndpointViewModel> Endpoints { get; } = [];

        public ObservableCollection<TornadoAdapterCheckViewModel> TornadoAdapterChecks { get; } = [];

        public ObservableCollection<PocRequirementViewModel> RequirementCoverage { get; } = [];

        public ObservableCollection<ScheduleMatchViewModel> ScheduleMatches { get; } = [];

        public ObservableCollection<InspectionQueueItemViewModel> InspectionQueue { get; } = [];

        public ObservableCollection<InspectionDetailItemViewModel> InspectionDetails { get; } = [];

        public ObservableCollection<LlmReviewRequestViewModel> LlmReviewRequests { get; } = [];

        public string LoginOperatorName
        {
            get => loginOperatorName;
            set => SetProperty(ref loginOperatorName, value);
        }

        public string LaunchMessage
        {
            get => launchMessage;
            set => SetProperty(ref launchMessage, value);
        }

        public Visibility LoginScreenVisibility
        {
            get => loginScreenVisibility;
            set => SetProperty(ref loginScreenVisibility, value);
        }

        public Visibility LaunchScreenVisibility
        {
            get => launchScreenVisibility;
            set => SetProperty(ref launchScreenVisibility, value);
        }

        public Visibility MainShellVisibility
        {
            get => mainShellVisibility;
            set => SetProperty(ref mainShellVisibility, value);
        }

        public void BeginLogin(string operatorName, string accessCode)
        {
            LoginOperatorName = string.IsNullOrWhiteSpace(operatorName) ? "producer" : operatorName.Trim();
            LaunchMessage = "TornadoAce";
            LoginScreenVisibility = Visibility.Collapsed;
            LaunchScreenVisibility = Visibility.Visible;
        }

        public void CompleteLogin()
        {
            LaunchScreenVisibility = Visibility.Collapsed;
            MainShellVisibility = Visibility.Visible;
            OperatorMessage = $"{LoginOperatorName} 제작자가 접속했습니다. 큐시트와 Scene 매핑 상태를 확인하세요.";
        }

        [RelayCommand]
        private void RefreshCueSheet()
        {
            selectedCueSheetIndex++;
            var selection = automationEngine.SelectCueSheet(selectedCueSheetIndex);
            activeCueSheet = selection.Record;
            activeSchedule = automationEngine.FindSchedule(activeCueSheet);
            activeScene = automationEngine.GenerateScene(activeCueSheet, workspace.ActiveTemplate);

            LastCueSheetSyncText = FormatCueSheetSelection(selection);
            OperatorMessage = $"{activeCueSheet.ProgramTitle} / {activeCueSheet.ProductName} 큐시트를 선택했습니다. {FormatScheduleMatch(activeSchedule)}";
            StatusCards[0].Metric = selection.TotalCount.ToString();
            StatusCards[0].Detail = $"선택 {selection.Position}/{selection.TotalCount}";
            ApplySceneSnapshot(activeScene);
        }

        [RelayCommand]
        private void GenerateScene()
        {
            activeScene = automationEngine.GenerateScene(activeCueSheet, workspace.ActiveTemplate);

            OperatorMessage = $"{activeCueSheet.CueSheetId} 데이터를 {activeScene.SceneName} Scene 스냅샷으로 생성했습니다.";
            StatusCards[1].Metric = workspace.ActiveTemplate.Mappings.Count.ToString();
            StatusCards[1].Detail = "필드 매핑 완료";
            ApplySceneSnapshot(activeScene);
        }

        [RelayCommand]
        private void RunInspection()
        {
            var summary = automationEngine.InspectWorkspace(workspace.ActiveTemplate);

            OperatorMessage = "Scene 추출값을 큐시트와 비교했습니다. 가격/구성 불일치는 높은 중요도로 분류합니다.";
            InspectionSummary = FormatInspectionSummary(summary);
            StatusCards[2].Metric = $"{summary.AverageMatchRate:0.0}%";
            StatusCards[2].Detail = $"확인 {summary.ReviewCount}건";
            LoadInspectionQueue(summary.Results);
            LoadInspectionDetails(summary.Results);
            LoadLlmReviewRequests(summary.Results);
        }

        [RelayCommand]
        private void RunPoc()
        {
            var result = automationEngine.RunFullPoc(selectedCueSheetIndex, workspace.ActiveTemplate);
            var logPath = pocRunLogWriter.Write(result);
            activeCueSheet = result.Selection.Record;
            activeSchedule = result.Schedule;
            activeScene = result.GeneratedScene;

            LastCueSheetSyncText = FormatCueSheetSelection(result.Selection);
            ActiveTemplateName = workspace.ActiveTemplate.TemplateName;
            InspectionSummary = FormatInspectionSummary(result.InspectionSummary);
            OperatorMessage = FormatPocRunSummary(result);
            PocRunLogText = $"로그 저장: {Path.GetFileName(logPath)}";

            StatusCards[0].Metric = result.Selection.TotalCount.ToString();
            StatusCards[0].Detail = $"ERP {FormatScheduleStatus(result.Schedule)}";
            StatusCards[1].Metric = workspace.ActiveTemplate.Mappings.Count.ToString();
            StatusCards[1].Detail = "Scene 생성 완료";
            StatusCards[2].Metric = $"{result.InspectionSummary.AverageMatchRate:0.0}%";
            StatusCards[2].Detail = $"LLM 후보 {result.LlmReviewRequests.Count}건";
            StatusCards[3].Metric = "Adapter";
            StatusCards[3].Detail = "Scene API Mock";

            ApplySceneSnapshot(result.GeneratedScene);
            LoadMappingValidation(result.MappingValidations);
            LoadTornadoAdapterChecks(result.AdapterChecks);
            LoadScheduleMatches();
            LoadInspectionQueue(result.InspectionSummary.Results);
            LoadInspectionDetails(result.InspectionSummary.Results);
            LoadLlmReviewRequests(result.InspectionSummary.Results);
        }

        private void LoadStatusCards()
        {
            StatusCards.Add(new StatusCardViewModel("큐시트 API", "12", "수신 대기", Symbol.Sync, Brush(0xFF5FD7D3)));
            StatusCards.Add(new StatusCardViewModel("Scene 매핑", "5", "템플릿 정의", Symbol.Map, Brush(0xFFB58BFF)));
            StatusCards.Add(new StatusCardViewModel("자동 검수", "98.7%", "목표 99%+", Symbol.Accept, Brush(0xFFD9B76E)));
            StatusCards.Add(new StatusCardViewModel("Tornado", "Adapter", "Mock SDK 경계", Symbol.Repair, Brush(0xFFC8FF17)));
        }

        private void LoadPipelineSteps()
        {
            PipelineSteps.Add(new PipelineStepViewModel("01", "큐시트/ERP 데이터 수신", "AI ON Studio / CJ OnStyle ERP", "PoC", 55, Brush(0xFF5FD7D3)));
            PipelineSteps.Add(new PipelineStepViewModel("02", "Data Field Mapping", "큐시트 필드 -> Tornado Scene 객체", "초안", 45, Brush(0xFFB58BFF)));
            PipelineSteps.Add(new PipelineStepViewModel("03", "Scene 생성/갱신", "Tornado2 우선, Tornado3 adapter ready", "PoC", 55, Brush(0xFFC8FF17)));
            PipelineSteps.Add(new PipelineStepViewModel("04", "Scene Data API 추출", "Text/Image visible object snapshot", "PoC", 50, Brush(0xFFD9B76E)));
            PipelineSteps.Add(new PipelineStepViewModel("05", "자동 검수 피드백", "Text Diffing + LLM 중요도 판정", "초안", 40, Brush(0xFFFF626E)));
        }

        private void LoadFieldMappings()
        {
            foreach (var mapping in workspace.ActiveTemplate.Mappings)
            {
                FieldMappings.Add(new FieldMappingViewModel(mapping.CueSheetField, mapping.SceneObjectName, mapping.Rule, mapping.Attribute));
            }
        }

        private void LoadMappingValidation()
        {
            LoadMappingValidation(automationEngine.ValidateMappingProfile(workspace.ActiveTemplate));
        }

        private void LoadMappingValidation(IEnumerable<MappingValidationResult> validations)
        {
            MappingValidations.Clear();

            foreach (var validation in validations)
            {
                MappingValidations.Add(new MappingValidationViewModel(
                    validation.CheckId,
                    validation.Title,
                    validation.Status,
                    validation.Detail,
                    SeverityBrush(validation.Severity)));
            }
        }

        private void LoadEndpoints()
        {
            Endpoints.Add(new IntegrationEndpointViewModel("큐시트 플랫폼", "GET /api/cuesheets/{broadcastDate}", "AI ON Studio", "Mock", Brush(0xFF5FD7D3)));
            Endpoints.Add(new IntegrationEndpointViewModel("ERP 편성", "GET /api/schedules/{programCode}", "CJ OnStyle ERP", "Mock", Brush(0xFFC8FF17)));
            Endpoints.Add(new IntegrationEndpointViewModel("Tornado Scene API", "POST /api/scenes/extract", "Tornado Adapter", "Mock", Brush(0xFFC8FF17)));
            Endpoints.Add(new IntegrationEndpointViewModel("LLM 검수", "POST /api/inspection/llm", "Internal LLM", "정책 확인", Brush(0xFFB58BFF)));
        }

        private void LoadTornadoAdapterChecks()
        {
            LoadTornadoAdapterChecks(automationEngine.GetTornadoAdapterChecks());
        }

        private void LoadTornadoAdapterChecks(IEnumerable<TornadoAdapterCheck> checks)
        {
            TornadoAdapterChecks.Clear();

            foreach (var check in checks)
            {
                TornadoAdapterChecks.Add(new TornadoAdapterCheckViewModel(
                    check.CheckId,
                    check.Name,
                    check.Status,
                    check.Evidence,
                    check.Status == "준비" ? Brush(0xFFD9B76E) : Brush(0xFFC8FF17)));
            }
        }

        private void LoadRequirementCoverage()
        {
            RequirementCoverage.Add(new PocRequirementViewModel("RFP-01", "큐시트 API 연동", "PoC", "JSON Mock 수신", Brush(0xFF5FD7D3)));
            RequirementCoverage.Add(new PocRequirementViewModel("RFP-02", "ERP 편성 연동", "PoC", "편성 JSON 매칭", Brush(0xFFC8FF17)));
            RequirementCoverage.Add(new PocRequirementViewModel("RFP-03", "Data Field Mapping", "PoC", "Scene 스냅샷 생성", Brush(0xFFC8FF17)));
            RequirementCoverage.Add(new PocRequirementViewModel("RFP-04", "Tornado Scene API", "PoC", "Mock adapter 추출", Brush(0xFFC8FF17)));
            RequirementCoverage.Add(new PocRequirementViewModel("RFP-05", "관리자 매핑 기능", "PoC", "프로파일 검증", Brush(0xFFC8FF17)));
            RequirementCoverage.Add(new PocRequirementViewModel("RFP-06", "1·2단계 자동 검수", "PoC", "필드 상세 Diff + LLM 후보", Brush(0xFF5FD7D3)));
        }

        private void LoadScheduleMatches()
        {
            ScheduleMatches.Clear();

            foreach (var cueSheet in workspace.CueSheets)
            {
                var schedule = automationEngine.FindSchedule(cueSheet);
                var isMatched = schedule is not null;

                ScheduleMatches.Add(new ScheduleMatchViewModel(
                    cueSheet.ProgramTitle,
                    $"{cueSheet.BroadcastTime:HH:mm} / {cueSheet.ProductName}",
                    schedule?.ProgramCode ?? "-",
                    schedule is null ? "편성 미확인" : $"{schedule.MerchandiserName} / {schedule.ProductCategory}",
                    isMatched ? "매칭" : "확인",
                    isMatched ? Brush(0xFFC8FF17) : Brush(0xFFD9B76E)));
            }
        }

        private void LoadInspectionQueue(IEnumerable<InspectionResult> results)
        {
            InspectionQueue.Clear();

            foreach (var item in results)
            {
                InspectionQueue.Add(new InspectionQueueItemViewModel(
                    item.ProgramTitle,
                    item.SceneName,
                    $"{item.MatchRate:0.0}%",
                    item.Severity,
                    item.Decision,
                    SeverityBrush(item.Severity)));
            }
        }

        private void LoadInspectionDetails(IEnumerable<InspectionResult> results)
        {
            InspectionDetails.Clear();

            var detailItems = results
                .SelectMany(result => result.FieldResults.Select(field => new { Result = result, Field = field }))
                .Where(item => item.Field.MatchRate < 99.5)
                .OrderBy(item => item.Field.MatchRate)
                .ThenBy(item => item.Result.CueSheetId)
                .Take(5);

            foreach (var item in detailItems)
            {
                InspectionDetails.Add(new InspectionDetailItemViewModel(
                    item.Result.CueSheetId,
                    item.Field.SceneObjectName,
                    item.Field.ExpectedText,
                    item.Field.ActualText,
                    $"{item.Field.MatchRate:0.0}%",
                    item.Field.Severity,
                    item.Field.Decision,
                    SeverityBrush(item.Field.Severity)));
            }
        }

        private void LoadLlmReviewRequests(IEnumerable<InspectionResult> results)
        {
            LlmReviewRequests.Clear();

            foreach (var request in automationEngine.BuildLlmReviewRequests(results))
            {
                LlmReviewRequests.Add(new LlmReviewRequestViewModel(
                    request.RequestId,
                    request.ProgramTitle,
                    request.SceneName,
                    request.RecommendedPriority,
                    request.AuditSummary,
                    request.PromptKey,
                    SeverityBrush(request.RecommendedPriority)));
            }
        }

        private void ApplySceneSnapshot(SceneDataSnapshot scene)
        {
            SceneSnapshotLabel = $"{scene.SceneName} / {scene.VisibleTextObjects.Count} text objects";
            SceneSnapshotText = scene.ToPreviewJson();
        }

        private static string FormatCueSheetSelection(CueSheetSelection selection)
        {
            return $"목 데이터 {selection.Position}/{selection.TotalCount} · {selection.Record.BroadcastTime:HH:mm}";
        }

        private static string FormatInspectionSummary(PocInspectionSummary summary)
        {
            return $"통과 {summary.PassedCount}건 / 확인 {summary.ReviewCount}건 / 평균 {summary.AverageMatchRate:0.0}%";
        }

        private static string FormatScheduleMatch(ErpScheduleRecord? schedule)
        {
            return schedule is null
                ? "ERP 편성은 확인 대기입니다."
                : $"ERP 편성 {schedule.ProgramCode}와 매칭됐습니다.";
        }

        private static string FormatScheduleStatus(ErpScheduleRecord? schedule)
        {
            return schedule is null ? "대기" : "매칭";
        }

        private static string FormatPocRunSummary(PocRunResult result)
        {
            var scheduleText = result.Schedule is null ? "ERP 미확인" : result.Schedule.ProgramCode;
            return $"PoC 실행 완료: {result.Selection.Record.CueSheetId} / {scheduleText} / {result.GeneratedScene.SceneName} / 검수 확인 {result.InspectionSummary.ReviewCount}건 / LLM 후보 {result.LlmReviewRequests.Count}건";
        }

        private static SolidColorBrush SeverityBrush(string severity)
        {
            return severity switch
            {
                "High" => Brush(0xFFFF626E),
                "Medium" => Brush(0xFFD9B76E),
                _ => Brush(0xFFC8FF17)
            };
        }

        private static SolidColorBrush Brush(uint argb)
        {
            return new SolidColorBrush(Color.FromArgb(
                (byte)(argb >> 24),
                (byte)(argb >> 16),
                (byte)(argb >> 8),
                (byte)argb));
        }
    }
}
