using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;

namespace Darkmatter.Libs.PlayerPrefs
{
    /// <summary>
    /// Fire-and-forget retry for keys stuck in <see cref="LocalWriteTracker.WriteState.PendingWrite"/>.
    /// Single-flight per key. Uses <see cref="CancellationToken.None"/> so a caller-scoped
    /// cancellation (e.g. load completing) won't abort an in-flight POST.
    /// On success, marks the key synced. Exceptions are swallowed and logged.
    /// </summary>
    public static class PendingWriteResync
    {
        private static readonly HashSet<string> InFlight = new();

        [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
        static void ResetDomain() { lock (InFlight) InFlight.Clear(); }

        /// <summary>
        /// Schedules a resync POST for <paramref name="key"/> if one isn't already running.
        /// </summary>
        /// <param name="key">Tracker key to mark synced on success.</param>
        /// <param name="post">POST closure; returns true on success.</param>
        public static void Schedule(string key, Func<CancellationToken, UniTask<bool>> post)
        {
            if (string.IsNullOrEmpty(key) || post == null) return;

            lock (InFlight)
            {
                if (!InFlight.Add(key)) return;
            }

            RunAsync(key, post).Forget();
        }

        private static async UniTaskVoid RunAsync(string key, Func<CancellationToken, UniTask<bool>> post)
        {
            try
            {
                var ok = await post(CancellationToken.None);
                if (ok) LocalWriteTracker.MarkSynced(key);
            }
            catch (Exception e)
            {
                Debug.LogWarning($"[PendingWriteResync] '{key}' failed: {e.Message}");
            }
            finally
            {
                lock (InFlight) InFlight.Remove(key);
            }
        }
    }
}
