using System.Text.Json;
using MBN_STOCK_WEBVIEW.LegacyApplication;
using MBN_STOCK_WEBVIEW.LegacyBridge;

namespace MBN_STOCK_WEBVIEW.LegacyBridge.Tests;

public sealed class LegacyOperatorSettingsBridgeTests
{
    [Theory]
    [InlineData("design", LegacyOperatorFolderKind.Design)]
    [InlineData("resource", LegacyOperatorFolderKind.Resource)]
    [InlineData("background", LegacyOperatorFolderKind.Background)]
    public void ParseChooseFolder_AcceptsOnlyClosedFolderKinds(
        string wireKind,
        LegacyOperatorFolderKind expectedKind)
    {
        var json =
            $"{{\"type\":\"choose-operator-folder\",\"payload\":{{\"kind\":\"{wireKind}\"}}}}";

        Assert.True(LegacyBridgeProtocol.TryParseIntent(json, out var parsed, out var error));
        Assert.Null(error);
        var intent = Assert.IsType<LegacyChooseOperatorFolderIntent>(parsed);
        Assert.Equal(expectedKind, intent.Kind);
    }

    [Theory]
    [InlineData("design", LegacyOperatorFolderKind.Design)]
    [InlineData("resource", LegacyOperatorFolderKind.Resource)]
    [InlineData("background", LegacyOperatorFolderKind.Background)]
    public void ParseResetFolder_AcceptsOnlyClosedFolderKinds(
        string wireKind,
        LegacyOperatorFolderKind expectedKind)
    {
        var json =
            $"{{\"type\":\"reset-operator-folder\",\"payload\":{{\"kind\":\"{wireKind}\"}}}}";

        Assert.True(LegacyBridgeProtocol.TryParseIntent(json, out var parsed, out var error));
        Assert.Null(error);
        var intent = Assert.IsType<LegacyResetOperatorFolderIntent>(parsed);
        Assert.Equal(expectedKind, intent.Kind);
    }

    [Theory]
    [InlineData(true)]
    [InlineData(false)]
    public void ParseNavigationExpanded_RequiresAnExactBoolean(bool expanded)
    {
        var json =
            $"{{\"type\":\"set-operator-navigation-expanded\",\"payload\":{{\"expanded\":{expanded.ToString().ToLowerInvariant()}}}}}";

        Assert.True(LegacyBridgeProtocol.TryParseIntent(json, out var parsed, out var error));
        Assert.Null(error);
        var intent = Assert.IsType<LegacySetOperatorNavigationExpandedIntent>(parsed);
        Assert.Equal(expanded, intent.Expanded);
    }

    [Theory]
    [InlineData(
        "system",
        "automatic",
        "stockCut",
        LegacyOperatorColorTheme.System,
        LegacyOperatorViewMode.Automatic,
        LegacyOperatorStartWorkspace.StockCut)]
    [InlineData(
        "light",
        "compact",
        "lastWorkspace",
        LegacyOperatorColorTheme.Light,
        LegacyOperatorViewMode.Compact,
        LegacyOperatorStartWorkspace.LastWorkspace)]
    [InlineData(
        "dark",
        "cards",
        "stockCut",
        LegacyOperatorColorTheme.Dark,
        LegacyOperatorViewMode.Cards,
        LegacyOperatorStartWorkspace.StockCut)]
    public void ParseAppearance_AcceptsOnlyClosedValues(
        string colorTheme,
        string viewMode,
        string startWorkspace,
        LegacyOperatorColorTheme expectedColorTheme,
        LegacyOperatorViewMode expectedViewMode,
        LegacyOperatorStartWorkspace expectedStartWorkspace)
    {
        var json =
            $"{{\"type\":\"set-operator-appearance\",\"payload\":{{\"viewMode\":\"{viewMode}\",\"startWorkspace\":\"{startWorkspace}\",\"colorTheme\":\"{colorTheme}\"}}}}";

        Assert.True(LegacyBridgeProtocol.TryParseIntent(json, out var parsed, out var error));
        Assert.Null(error);
        var intent = Assert.IsType<LegacySetOperatorAppearanceIntent>(parsed);
        Assert.Equal(expectedColorTheme, intent.ColorTheme);
        Assert.Equal(expectedViewMode, intent.ViewMode);
        Assert.Equal(expectedStartWorkspace, intent.StartWorkspace);
    }

    [Theory]
    [InlineData("{\"type\":\"choose-operator-folder\",\"payload\":{}}")]
    [InlineData("{\"type\":\"choose-operator-folder\",\"payload\":{\"kind\":\"settings\"}}")]
    [InlineData("{\"type\":\"choose-operator-folder\",\"payload\":{\"kind\":\"Design\"}}")]
    [InlineData("{\"type\":\"choose-operator-folder\",\"payload\":{\"kind\":1}}")]
    [InlineData("{\"type\":\"choose-operator-folder\",\"payload\":{\"kind\":\"design\",\"path\":\"C:\\\\Cuts\"}}")]
    [InlineData("{\"type\":\"reset-operator-folder\",\"payload\":{\"kind\":\"resource\",\"extra\":false}}")]
    [InlineData("{\"type\":\"reset-operator-folder\",\"payload\":{\"kind\":\"resource\",\"kind\":\"design\"}}")]
    [InlineData("{\"type\":\"set-operator-navigation-expanded\",\"payload\":{}}")]
    [InlineData("{\"type\":\"set-operator-navigation-expanded\",\"payload\":{\"expanded\":\"true\"}}")]
    [InlineData("{\"type\":\"set-operator-navigation-expanded\",\"payload\":{\"expanded\":true,\"path\":\"C:\\\\Config\"}}")]
    [InlineData("{\"type\":\"set-operator-appearance\",\"payload\":{\"colorTheme\":\"system\",\"viewMode\":\"automatic\"}}")]
    [InlineData("{\"type\":\"set-operator-appearance\",\"payload\":{\"colorTheme\":\"mbn\",\"viewMode\":\"automatic\",\"startWorkspace\":\"stockCut\"}}")]
    [InlineData("{\"type\":\"set-operator-appearance\",\"payload\":{\"colorTheme\":\"system\",\"viewMode\":\"grid\",\"startWorkspace\":\"stockCut\"}}")]
    [InlineData("{\"type\":\"set-operator-appearance\",\"payload\":{\"colorTheme\":\"system\",\"viewMode\":\"automatic\",\"startWorkspace\":\"other\"}}")]
    [InlineData("{\"type\":\"set-operator-appearance\",\"payload\":{\"colorTheme\":\"system\",\"viewMode\":\"automatic\",\"startWorkspace\":\"stockCut\",\"extra\":true}}")]
    [InlineData("{\"type\":\"set-operator-appearance\",\"payload\":{\"colorTheme\":\"system\",\"colorTheme\":\"dark\",\"viewMode\":\"automatic\",\"startWorkspace\":\"stockCut\"}}")]
    public void ParseSettingsIntents_RejectsMissingUnknownAndExtraAuthority(string json)
    {
        Assert.False(LegacyBridgeProtocol.TryParseIntent(json, out var parsed, out _));
        Assert.Null(parsed);
    }

    [Fact]
    public void SerializeState_ProjectsOperatorSettingsWithClosedWireNames()
    {
        var settings = new LegacyOperatorSettingsSnapshot(
            17,
            new LegacyOperatorFolderSnapshot("D:\\Design", true, true, "사용 가능"),
            new LegacyOperatorFolderSnapshot("D:\\Resource", true, false, "Res 폴더 없음"),
            new LegacyOperatorFolderSnapshot("앱 기본 배경", false, true, "기본값"),
            NavigationExpanded: false,
            ColorTheme: LegacyOperatorColorTheme.Dark,
            ViewMode: LegacyOperatorViewMode.Cards,
            StartWorkspace: LegacyOperatorStartWorkspace.LastWorkspace,
            RestartRequired: true,
            Message: "재시작 후 적용됩니다.",
            MessageKind: LegacyOperatorSettingsMessageKind.Warning,
            AppVersion: "0.1.0.0",
            OracleState: "연결됨",
            MariaState: "연결 끊김",
            DatabasePollingSeconds: 10);

        var json = LegacyBridgeProtocol.SerializeState(
            CreateSnapshot(),
            operatorSettings: settings);

        using var document = JsonDocument.Parse(json);
        var projected = document.RootElement
            .GetProperty("payload")
            .GetProperty("operatorSettings");

        Assert.Equal(17, projected.GetProperty("revision").GetInt64());
        Assert.Equal("D:\\Design", projected.GetProperty("design")
            .GetProperty("displayName").GetString());
        Assert.True(projected.GetProperty("design").GetProperty("isCustom").GetBoolean());
        Assert.True(projected.GetProperty("design").GetProperty("isValid").GetBoolean());
        Assert.Equal("사용 가능", projected.GetProperty("design")
            .GetProperty("status").GetString());
        Assert.False(projected.GetProperty("resource").GetProperty("isValid").GetBoolean());
        Assert.False(projected.GetProperty("background").GetProperty("isCustom").GetBoolean());
        Assert.False(projected.GetProperty("navigationExpanded").GetBoolean());
        Assert.Equal("dark", projected.GetProperty("colorTheme").GetString());
        Assert.Equal("cards", projected.GetProperty("viewMode").GetString());
        Assert.Equal(
            "lastWorkspace",
            projected.GetProperty("startWorkspace").GetString());
        Assert.True(projected.GetProperty("restartRequired").GetBoolean());
        Assert.Equal("재시작 후 적용됩니다.", projected.GetProperty("message").GetString());
        Assert.Equal("warning", projected.GetProperty("messageKind").GetString());
        Assert.Equal("0.1.0.0", projected.GetProperty("appVersion").GetString());
        Assert.Equal("연결됨", projected.GetProperty("oracleState").GetString());
        Assert.Equal("연결 끊김", projected.GetProperty("mariaState").GetString());
        Assert.Equal(10, projected.GetProperty("databasePollingSeconds").GetInt32());
        Assert.False(projected.TryGetProperty("Design", out _));
        Assert.False(projected.GetProperty("design").TryGetProperty("DisplayName", out _));
    }

    [Fact]
    public void SerializeState_UsesNullOperatorSettingsWhenNotProvided()
    {
        using var document = JsonDocument.Parse(
            LegacyBridgeProtocol.SerializeState(CreateSnapshot()));

        Assert.Equal(
            JsonValueKind.Null,
            document.RootElement.GetProperty("payload")
                .GetProperty("operatorSettings").ValueKind);
    }

    private static LegacyOperatorSnapshot CreateSnapshot() => new(
        1,
        string.Empty,
        [],
        null,
        [],
        [],
        null,
        string.Empty,
        LegacyOperatorStatusKind.Neutral);
}
