using System.Text.Json;
using MBN_STOCK_WEBVIEW.Core.Playout;
using MBN_STOCK_WEBVIEW.Core.Playout.Scenes;

namespace MBN_STOCK_WEBVIEW.Core.Tests;

public sealed class LegacyCutRequirementManifestTests
{
    private static readonly StringComparer PathComparer = StringComparer.OrdinalIgnoreCase;

    [Fact]
    public void Critical_builder_assets_match_the_closed_preflight_manifest()
    {
        var manifest = ReadManifest();
        var actual = new HashSet<string>(PathComparer);
        var directions = new[]
        {
            ScenePriceDirection.Up,
            ScenePriceDirection.Flat,
            ScenePriceDirection.Down
        };

        foreach (var direction in directions)
        {
            AddAssets(actual, new S5006SceneMutationBuilder().Build(new S5006SceneData(
                LegacyDomesticEquityMarket.Kospi,
                "fixture",
                direction,
                1,
                1,
                1m,
                1,
                1m,
                1,
                1m,
                1,
                1m)));

            foreach (var target in Enum.GetValues<S6001QuoteTarget>())
            {
                AddAssets(actual, new S6001SceneMutationBuilder().Build(new S6001SceneData(
                    target,
                    "fixture",
                    1m,
                    1m,
                    1m,
                    direction)));
            }
        }

        var expected = manifest.Assets
            .Where(asset => asset.Builder is "s5006" or "s6001" or "shared-price-direction")
            .Select(asset => asset.Path)
            .ToHashSet(PathComparer);

        Assert.Equal(expected.Count, actual.Count);
        Assert.Empty(expected.Except(actual, PathComparer));
        Assert.Empty(actual.Except(expected, PathComparer));
    }

    [Fact]
    public void Manifest_is_relative_closed_and_includes_all_s6001_videos()
    {
        var manifest = ReadManifest();

        Assert.Equal(1, manifest.SchemaVersion);
        Assert.Equal(34, manifest.ReachableBuilders);
        Assert.Equal(45, manifest.ActiveAliases.Count);
        Assert.Equal(23, manifest.Assets.Count);
        Assert.Equal(
            13,
            manifest.Assets
                .Where(asset => asset.Builder == "s6001" && asset.Kind == "Video")
                .Select(asset => asset.Path)
                .Distinct(PathComparer)
                .Count());
        Assert.Contains(
            manifest.Assets,
            asset => asset.Builder == "s5006" &&
                PathComparer.Equals(asset.Path, @"Video\큐브배경.vrv"));

        Assert.All(manifest.Assets, asset =>
        {
            Assert.Contains(asset.Kind, new[] { "Image", "Texture", "Video" });
            Assert.False(Path.IsPathRooted(asset.Path));
            Assert.DoesNotContain(
                "..",
                asset.Path.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
        });
    }

    private static void AddAssets(
        ISet<string> paths,
        IEnumerable<PlayoutMutation> mutations)
    {
        foreach (var mutation in mutations)
        {
            switch (mutation)
            {
                case PlayoutSetAssetValue asset:
                    paths.Add(asset.AssetPath);
                    break;
                case PlayoutSetBackgroundTexture texture:
                    paths.Add(texture.AssetPath);
                    break;
                case PlayoutSetBackgroundVideo video:
                    paths.Add(video.AssetPath);
                    break;
            }
        }
    }

    private static LegacyCutRequirementManifest ReadManifest()
    {
        var path = Path.Combine(
            AppContext.BaseDirectory,
            "Fixtures",
            "LegacyCutRequirements.json");
        var manifest = JsonSerializer.Deserialize<LegacyCutRequirementManifest>(
            File.ReadAllText(path),
            new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
        return Assert.IsType<LegacyCutRequirementManifest>(manifest);
    }

    private sealed record LegacyCutRequirementManifest(
        int SchemaVersion,
        int ReachableBuilders,
        IReadOnlyList<string> ActiveAliases,
        IReadOnlyList<LegacyBuilderAssetRequirement> Assets);

    private sealed record LegacyBuilderAssetRequirement(
        string Builder,
        string Kind,
        string Path);
}
