using Microsoft.AspNetCore.WebUtilities;

namespace RolemasterDb.App.Frontend.AppState;

public sealed class TableContextUrlSerializer
{
    private const string TableKey = "table";
    private const string GroupKey = "group";
    private const string ColumnKey = "column";
    private const string RollBandKey = "rollBand";
    private const string RollJumpKey = "roll";
    private const string ResultIdKey = "result";
    private const string ModeKey = "mode";
    private const string QueueScopeKey = "scope";

    public TableContextSnapshot Parse(string uri)
    {
        var currentUri = new Uri(uri, UriKind.Absolute);
        var query = QueryHelpers.ParseQuery(currentUri.Query);

        return new TableContextSnapshot(ReadValue(query, TableKey), ReadValue(query, GroupKey), ReadValue(query, ColumnKey), ReadValue(query, RollBandKey), ReadInt(query, RollJumpKey), ReadInt(query, ResultIdKey), ReadMode(ReadValue(query, ModeKey)), ReadValue(query, QueueScopeKey));
    }

    public string BuildRelativeUri(string basePath, TableContextSnapshot context)
    {
        var parameters = new Dictionary<string, string?>();
        AddIfPresent(parameters, TableKey, context.TableSlug);
        AddIfPresent(parameters, GroupKey, context.GroupKey);
        AddIfPresent(parameters, ColumnKey, context.ColumnKey);
        AddIfPresent(parameters, RollBandKey, context.RollBand);
        AddIfPresent(parameters, RollJumpKey, context.RollJump?.ToString());
        AddIfPresent(parameters, ResultIdKey, context.ResultId?.ToString());
        AddIfPresent(parameters, ModeKey, WriteMode(context.Mode));
        AddIfPresent(parameters, QueueScopeKey, context.QueueScope);

        return parameters.Count == 0 ? basePath : QueryHelpers.AddQueryString(basePath, parameters);
    }

    private static void AddIfPresent(IDictionary<string, string?> parameters, string key, string? value)
    {
        if (!string.IsNullOrWhiteSpace(value))
        {
            parameters[key] = value.Trim();
        }
    }

    private static string? ReadValue(IReadOnlyDictionary<string, Microsoft.Extensions.Primitives.StringValues> query, string key) =>
        query.TryGetValue(key, out var value) ? value.ToString() : null;

    private static int? ReadInt(IReadOnlyDictionary<string, Microsoft.Extensions.Primitives.StringValues> query, string key)
    {
        var value = ReadValue(query, key);
        return int.TryParse(value, out var parsed) ? parsed : null;
    }

    private static TableContextMode? ReadMode(string? value) =>
        value?.Trim().ToLowerInvariant() switch
        {
            "reference"   => TableContextMode.Reference,
            "curation"    => TableContextMode.Curation,
            "diagnostics" => TableContextMode.Diagnostics,
            _             => null
        };

    private static string? WriteMode(TableContextMode? mode) =>
        mode switch
        {
            TableContextMode.Reference   => "reference",
            TableContextMode.Curation    => "curation",
            TableContextMode.Diagnostics => "diagnostics",
            _                            => null
        };
}