using System.Text.Json;
using TornadoAce_CJOnStyle.Domain;

namespace TornadoAce_CJOnStyle.Services
{
    public sealed class AutomationWorkspace
    {
        private AutomationWorkspace(
            IReadOnlyList<CueSheetRecord> cueSheets,
            IReadOnlyList<ErpScheduleRecord> erpSchedules,
            SceneTemplateDefinition activeTemplate,
            SceneDataSnapshot activeScene,
            IReadOnlyList<InspectionResult> inspectionResults)
        {
            CueSheets = cueSheets;
            ErpSchedules = erpSchedules;
            ActiveTemplate = activeTemplate;
            ActiveScene = activeScene;
            InspectionResults = inspectionResults;
        }

        public IReadOnlyList<CueSheetRecord> CueSheets { get; }

        public IReadOnlyList<ErpScheduleRecord> ErpSchedules { get; }

        public SceneTemplateDefinition ActiveTemplate { get; }

        public SceneDataSnapshot ActiveScene { get; }

        public IReadOnlyList<InspectionResult> InspectionResults { get; }

        public static AutomationWorkspace CreateDemo()
        {
            return TryCreateFromSeedFile() ?? CreateEmbeddedDemo();
        }

        private static AutomationWorkspace? TryCreateFromSeedFile()
        {
            var seedPath = Path.Combine(AppContext.BaseDirectory, "Data", "PocWorkspace.json");
            if (!File.Exists(seedPath))
            {
                return null;
            }

            var json = File.ReadAllText(seedPath);
            var seed = JsonSerializer.Deserialize<WorkspaceSeed>(
                json,
                new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

            if (seed?.CueSheets is not { Count: > 0 } cueSheets
                || seed.ActiveTemplate is null
                || seed.ActiveScene is null)
            {
                return null;
            }

            var template = seed.ActiveTemplate.ToDomain();
            var scene = seed.ActiveScene.ToDomain();
            var schedules = seed.ErpSchedules?
                .Select(schedule => schedule.ToDomain())
                .ToArray() ?? [];
            var inspections = seed.InspectionResults
                .Select(inspection => inspection.ToDomain())
                .ToArray();

            return new AutomationWorkspace(
                cueSheets.Select(cueSheet => cueSheet.ToDomain()).ToArray(),
                schedules,
                template,
                scene,
                inspections);
        }

        private static AutomationWorkspace CreateEmbeddedDemo()
        {
            var cueSheets = new[]
            {
                new CueSheetRecord("CJ-20260817-001", new DateTime(2026, 8, 17, 9, 0, 0), "최화정쇼", "비비안 컴포트 패키지", "79,900원", "브라 4종 + 팬티 4종", "ARS 10% 할인"),
                new CueSheetRecord("CJ-20260817-002", new DateTime(2026, 8, 17, 11, 0, 0), "동가게", "프리미엄 한우 세트", "69,900원", "1등급 등심 1.2kg", "무이자 5개월"),
                new CueSheetRecord("CJ-20260817-003", new DateTime(2026, 8, 17, 14, 0, 0), "스타일 라이브", "썸머 린넨 셋업", "59,900원", "자켓 + 팬츠", "앱 주문 추가 적립")
            };

            var schedules = new[]
            {
                new ErpScheduleRecord("PGM-CHOI-0900", "최화정쇼", new DateTime(2026, 8, 17, 9, 0, 0), 60, "CJ OnStyle Live", "MD 이수진", "패션 이너웨어"),
                new ErpScheduleRecord("PGM-DONG-1100", "동가게", new DateTime(2026, 8, 17, 11, 0, 0), 50, "CJ OnStyle Live", "MD 박정우", "신선식품"),
                new ErpScheduleRecord("PGM-STYLE-1400", "스타일 라이브", new DateTime(2026, 8, 17, 14, 0, 0), 70, "CJ OnStyle Live", "MD 김하린", "패션 의류")
            };

            var mappings = new[]
            {
                new FieldMappingDefinition("programTitle", "TXT_PROGRAM", "Text", "trim"),
                new FieldMappingDefinition("productName", "TXT_PRODUCT", "Text", "normalize-space"),
                new FieldMappingDefinition("priceText", "TXT_PRICE", "Text", "currency-text"),
                new FieldMappingDefinition("compositionText", "TXT_COMPOSITION", "Text", "line-break-safe"),
                new FieldMappingDefinition("promotionText", "TXT_PROMOTION", "Text", "special-char-exception")
            };

            var template = new SceneTemplateDefinition("CJ_PRICE_LOWER_01", "가격형 하단 자막 / Tornado Scene", "Tornado2 primary, Tornado3 ready", mappings);

            var scene = new SceneDataSnapshot(
                "CJ_PRICE_LOWER_01_0900.tscn",
                template.TemplateId,
                new Dictionary<string, string>
                {
                    ["TXT_PROGRAM"] = "최화정쇼",
                    ["TXT_PRODUCT"] = "비비안 컴포트 패키지",
                    ["TXT_PRICE"] = "79,900원",
                    ["TXT_COMPOSITION"] = "브라 4종 + 팬티 4종",
                    ["TXT_PROMOTION"] = "ARS 10% 할인"
                },
                new[] { @"D:\CJOnStyle\Products\VIVIEN\main.png" });

            var inspections = new[]
            {
                new InspectionResult("CJ-20260817-001", "최화정쇼", "CJ_PRICE_LOWER_01_0900.tscn", 100, "Low", "1차 통과"),
                new InspectionResult("CJ-20260817-002", "동가게", "CJ_PRICE_LOWER_01_1100.tscn", 96.4, "High", "가격 불일치 확인"),
                new InspectionResult("CJ-20260817-003", "스타일 라이브", "CJ_PRICE_LOWER_01_1400.tscn", 98.1, "Medium", "특수문자 예외 후보")
            };

            return new AutomationWorkspace(cueSheets, schedules, template, scene, inspections);
        }

        private sealed record WorkspaceSeed(
            List<CueSheetSeed> CueSheets,
            List<ErpScheduleSeed>? ErpSchedules,
            SceneTemplateSeed ActiveTemplate,
            SceneDataSeed ActiveScene,
            List<InspectionSeed> InspectionResults);

        private sealed record CueSheetSeed(
            string CueSheetId,
            DateTime BroadcastTime,
            string ProgramTitle,
            string ProductName,
            string PriceText,
            string CompositionText,
            string PromotionText)
        {
            public CueSheetRecord ToDomain()
            {
                return new CueSheetRecord(CueSheetId, BroadcastTime, ProgramTitle, ProductName, PriceText, CompositionText, PromotionText);
            }
        }

        private sealed record ErpScheduleSeed(
            string ProgramCode,
            string ProgramTitle,
            DateTime BroadcastTime,
            int DurationMinutes,
            string ChannelName,
            string MerchandiserName,
            string ProductCategory)
        {
            public ErpScheduleRecord ToDomain()
            {
                return new ErpScheduleRecord(
                    ProgramCode,
                    ProgramTitle,
                    BroadcastTime,
                    DurationMinutes,
                    ChannelName,
                    MerchandiserName,
                    ProductCategory);
            }
        }

        private sealed record SceneTemplateSeed(
            string TemplateId,
            string TemplateName,
            string TornadoVersion,
            List<FieldMappingSeed> Mappings)
        {
            public SceneTemplateDefinition ToDomain()
            {
                return new SceneTemplateDefinition(
                    TemplateId,
                    TemplateName,
                    TornadoVersion,
                    Mappings.Select(mapping => mapping.ToDomain()).ToArray());
            }
        }

        private sealed record FieldMappingSeed(
            string CueSheetField,
            string SceneObjectName,
            string Attribute,
            string Rule)
        {
            public FieldMappingDefinition ToDomain()
            {
                return new FieldMappingDefinition(CueSheetField, SceneObjectName, Attribute, Rule);
            }
        }

        private sealed record SceneDataSeed(
            string SceneName,
            string TemplateId,
            Dictionary<string, string> VisibleTextObjects,
            List<string> ImagePaths)
        {
            public SceneDataSnapshot ToDomain()
            {
                return new SceneDataSnapshot(SceneName, TemplateId, VisibleTextObjects, ImagePaths);
            }
        }

        private sealed record InspectionSeed(
            string CueSheetId,
            string ProgramTitle,
            string SceneName,
            double MatchRate,
            string Severity,
            string Decision)
        {
            public InspectionResult ToDomain()
            {
                return new InspectionResult(CueSheetId, ProgramTitle, SceneName, MatchRate, Severity, Decision);
            }
        }
    }
}
