using System.Text.Json;
using RolemasterDb.App.Features;

namespace RolemasterDb.App.Frontend.AppState;

public sealed class TableContextState(
    BrowserStorageService browserStorage,
    TableContextUrlSerializer serializer)
{
    private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web);

    public async Task<TableContextSnapshot> RestoreAsync(
        string currentUri,
        string destination,
        IReadOnlyList<CriticalTableReference> availableTables,
        TableContextMode defaultMode)
    {
        var routeContext = serializer.Parse(currentUri);
        if (!string.IsNullOrWhiteSpace(routeContext.TableSlug))
        {
            return Normalize(routeContext, availableTables, defaultMode);
        }

        try
        {
            var storedValue = await browserStorage.GetItemAsync(BrowserStorageKeys.TableContext(destination));
            if (!string.IsNullOrWhiteSpace(storedValue))
            {
                var storedContext = JsonSerializer.Deserialize<TableContextSnapshot>(storedValue, SerializerOptions);
                if (storedContext is not null)
                {
                    return Normalize(storedContext, availableTables, defaultMode);
                }
            }
        }
        catch (InvalidOperationException)
        {
            // JS interop is unavailable during prerender. Fall back to route/default context.
        }
        catch (JsonException)
        {
            // Ignore malformed storage payloads and fall back to route/default context.
        }

        return Normalize(routeContext, availableTables, defaultMode);
    }

    public Task PersistAsync(string destination, TableContextSnapshot context)
    {
        var serialized = JsonSerializer.Serialize(context, SerializerOptions);
        return browserStorage.SetItemAsync(BrowserStorageKeys.TableContext(destination), serialized).AsTask();
    }

    public string BuildUri(string basePath, TableContextSnapshot context) =>
        serializer.BuildRelativeUri(basePath, context);

    public string ResolveTableSlug(IReadOnlyList<CriticalTableReference> availableTables, string? preferredSlug)
    {
        if (availableTables.Count == 0)
        {
            return string.Empty;
        }

        if (!string.IsNullOrWhiteSpace(preferredSlug) &&
            availableTables.Any(item => string.Equals(item.Key, preferredSlug, StringComparison.OrdinalIgnoreCase)))
        {
            return preferredSlug;
        }

        return availableTables[0].Key;
    }

    private TableContextSnapshot Normalize(
        TableContextSnapshot context,
        IReadOnlyList<CriticalTableReference> availableTables,
        TableContextMode defaultMode) =>
        context with
        {
            TableSlug = ResolveTableSlug(availableTables, context.TableSlug),
            Mode = context.Mode ?? defaultMode
        };
}
