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

namespace MBN_STOCK_WEBVIEW.LegacyBridge;

public enum LegacyOperatorFolderKind
{
    Design,
    Resource,
    Background
}

public enum LegacyOperatorSettingsMessageKind
{
    Neutral,
    Information,
    Success,
    Warning,
    Error
}

public sealed record LegacyChooseOperatorFolderIntent(LegacyOperatorFolderKind Kind)
    : LegacyUiIntent;

public sealed record LegacyResetOperatorFolderIntent(LegacyOperatorFolderKind Kind)
    : LegacyUiIntent;

public sealed record LegacySetOperatorNavigationExpandedIntent(bool Expanded)
    : LegacyUiIntent;

public sealed record LegacySetOperatorAppearanceIntent(
    LegacyOperatorColorTheme ColorTheme,
    LegacyOperatorViewMode ViewMode,
    LegacyOperatorStartWorkspace StartWorkspace)
    : LegacyUiIntent;

public sealed record LegacyOperatorFolderSnapshot(
    string DisplayName,
    bool IsCustom,
    bool IsValid,
    string Status);

public sealed record LegacyOperatorSettingsSnapshot(
    long Revision,
    LegacyOperatorFolderSnapshot Design,
    LegacyOperatorFolderSnapshot Resource,
    LegacyOperatorFolderSnapshot Background,
    bool NavigationExpanded,
    LegacyOperatorColorTheme ColorTheme,
    LegacyOperatorViewMode ViewMode,
    LegacyOperatorStartWorkspace StartWorkspace,
    bool RestartRequired,
    string Message,
    LegacyOperatorSettingsMessageKind MessageKind,
    string AppVersion,
    string OracleState,
    string MariaState,
    int DatabasePollingSeconds);

internal static class LegacyOperatorSettingsUiIntentParser
{
    public static LegacyUiIntent? Parse(string type, JsonElement payload) => type switch
    {
        "choose-operator-folder" => ParseFolder(
            payload,
            static kind => new LegacyChooseOperatorFolderIntent(kind)),
        "reset-operator-folder" => ParseFolder(
            payload,
            static kind => new LegacyResetOperatorFolderIntent(kind)),
        "set-operator-navigation-expanded" => ParseNavigationExpanded(payload),
        "set-operator-appearance" => ParseAppearance(payload),
        _ => null
    };

    private static LegacyUiIntent? ParseFolder(
        JsonElement payload,
        Func<LegacyOperatorFolderKind, LegacyUiIntent> factory)
    {
        if (!HasExactSingleProperty(payload, "kind", out var kindElement) ||
            kindElement.ValueKind != JsonValueKind.String)
        {
            return null;
        }

        var kind = kindElement.GetString() switch
        {
            "design" => LegacyOperatorFolderKind.Design,
            "resource" => LegacyOperatorFolderKind.Resource,
            "background" => LegacyOperatorFolderKind.Background,
            _ => (LegacyOperatorFolderKind?)null
        };

        return kind.HasValue ? factory(kind.Value) : null;
    }

    private static LegacyUiIntent? ParseNavigationExpanded(JsonElement payload)
    {
        if (!HasExactSingleProperty(payload, "expanded", out var expandedElement) ||
            expandedElement.ValueKind is not (JsonValueKind.True or JsonValueKind.False))
        {
            return null;
        }

        return new LegacySetOperatorNavigationExpandedIntent(expandedElement.GetBoolean());
    }

    private static LegacyUiIntent? ParseAppearance(JsonElement payload)
    {
        if (payload.ValueKind != JsonValueKind.Object)
        {
            return null;
        }

        string? colorThemeText = null;
        string? viewModeText = null;
        string? startWorkspaceText = null;
        var propertyCount = 0;
        foreach (var property in payload.EnumerateObject())
        {
            propertyCount++;
            if (property.Value.ValueKind != JsonValueKind.String)
            {
                return null;
            }

            var text = property.Value.GetString();
            switch (property.Name)
            {
                case "colorTheme" when colorThemeText is null:
                    colorThemeText = text;
                    break;
                case "viewMode" when viewModeText is null:
                    viewModeText = text;
                    break;
                case "startWorkspace" when startWorkspaceText is null:
                    startWorkspaceText = text;
                    break;
                default:
                    return null;
            }
        }

        if (propertyCount != 3)
        {
            return null;
        }

        var colorTheme = colorThemeText switch
        {
            "system" => LegacyOperatorColorTheme.System,
            "light" => LegacyOperatorColorTheme.Light,
            "dark" => LegacyOperatorColorTheme.Dark,
            _ => (LegacyOperatorColorTheme?)null
        };
        var viewMode = viewModeText switch
        {
            "automatic" => LegacyOperatorViewMode.Automatic,
            "compact" => LegacyOperatorViewMode.Compact,
            "cards" => LegacyOperatorViewMode.Cards,
            _ => (LegacyOperatorViewMode?)null
        };
        var startWorkspace = startWorkspaceText switch
        {
            "stockCut" => LegacyOperatorStartWorkspace.StockCut,
            "lastWorkspace" => LegacyOperatorStartWorkspace.LastWorkspace,
            _ => (LegacyOperatorStartWorkspace?)null
        };

        return colorTheme.HasValue && viewMode.HasValue && startWorkspace.HasValue
            ? new LegacySetOperatorAppearanceIntent(
                colorTheme.Value,
                viewMode.Value,
                startWorkspace.Value)
            : null;
    }

    private static bool HasExactSingleProperty(
        JsonElement payload,
        string propertyName,
        out JsonElement propertyValue)
    {
        propertyValue = default;
        if (payload.ValueKind != JsonValueKind.Object)
        {
            return false;
        }

        using var enumerator = payload.EnumerateObject();
        if (!enumerator.MoveNext() ||
            !string.Equals(enumerator.Current.Name, propertyName, StringComparison.Ordinal))
        {
            return false;
        }

        propertyValue = enumerator.Current.Value;
        return !enumerator.MoveNext();
    }
}
