using System.Text.Json;
using System.Text.Json.Serialization;
using ChessCubing.App.Models;

namespace ChessCubing.App.Services;

public sealed class MatchStore(BrowserBridge browser, UserSession userSession)
{
    public const string StorageKeyPrefix = "chesscubing-arena-state-v3";
    public const string WindowNameKeyPrefix = "chesscubing-arena-state-v3";

    private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web)
    {
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    };

    private bool _dirty;
    private long _lastPersistedAt;
    private string? _activeStorageKey;
    private string? _activeWindowNameKey;

    public MatchState? Current { get; private set; }

    public bool IsLoaded { get; private set; }

    public async Task EnsureLoadedAsync()
    {
        var storageScope = await SyncStorageScopeAsync();
        if (IsLoaded)
        {
            return;
        }

        try
        {
            var raw = await browser.ReadMatchJsonAsync(storageScope.StorageKey, storageScope.WindowNameKey);
            if (!string.IsNullOrWhiteSpace(raw))
            {
                var parsed = JsonSerializer.Deserialize<MatchState>(raw, JsonOptions);
                if (parsed is not null && MatchEngine.IsSupportedSchemaVersion(parsed.SchemaVersion))
                {
                    MatchEngine.NormalizeRecoveredMatch(parsed);
                    Current = parsed;
                }
            }
        }
        catch
        {
            Current = null;
        }

        IsLoaded = true;
        _lastPersistedAt = MatchEngine.NowUnixMs();
    }

    public void SetCurrent(MatchState? match)
    {
        Current = match;
        MarkDirty();
    }

    public void MarkDirty()
        => _dirty = true;

    public async Task SaveAsync()
    {
        var storageScope = await SyncStorageScopeAsync();
        if (!IsLoaded)
        {
            return;
        }

        if (Current is null)
        {
            await browser.ClearMatchAsync(storageScope.StorageKey, storageScope.WindowNameKey);
            _dirty = false;
            _lastPersistedAt = MatchEngine.NowUnixMs();
            return;
        }

        var json = JsonSerializer.Serialize(Current, JsonOptions);
        await browser.WriteMatchJsonAsync(storageScope.StorageKey, storageScope.WindowNameKey, json);
        _dirty = false;
        _lastPersistedAt = MatchEngine.NowUnixMs();
    }

    public async Task FlushIfDueAsync(long minimumIntervalMs = 1_000)
    {
        if (!_dirty)
        {
            return;
        }

        if (MatchEngine.NowUnixMs() - _lastPersistedAt < minimumIntervalMs)
        {
            return;
        }

        await SaveAsync();
    }

    public async Task ClearAsync()
    {
        var storageScope = await SyncStorageScopeAsync();
        Current = null;
        IsLoaded = true;
        _dirty = false;
        _lastPersistedAt = MatchEngine.NowUnixMs();
        await browser.ClearMatchAsync(storageScope.StorageKey, storageScope.WindowNameKey);
    }

    private async ValueTask<UserStorageScope> SyncStorageScopeAsync()
    {
        var storageScope = await userSession.GetStorageScopeAsync();
        if (_activeStorageKey is not null &&
            (_activeStorageKey != storageScope.StorageKey || _activeWindowNameKey != storageScope.WindowNameKey))
        {
            Current = null;
            IsLoaded = false;
            _dirty = false;
        }

        _activeStorageKey = storageScope.StorageKey;
        _activeWindowNameKey = storageScope.WindowNameKey;
        return storageScope;
    }
}
