using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Features.Progression;
using Darkmatter.Core.Data.Dynamic.Features.Progression;
using Darkmatter.Core.Enums.Features.Progression;
using Darkmatter.Features.Progression.Systems;
using UnityEngine;

public class ProgressionSystem : IProgressionSystem
{
    private readonly ProgressionRepository _repository;
    private readonly Dictionary<string, DrawingProgress> _records = new();
    private readonly HashSet<string> _completed = new();
    private readonly SemaphoreSlim _writeLock = new(1, 1);

    public IReadOnlyCollection<string> CompletedTemplateIds => _completed;

    public ProgressionSystem(ProgressionRepository repository)
    {
        _repository = repository;
    }

    public async UniTask LoadAsync()
    {
        await _repository.LoadAsync();
        _records.Clear();
        _completed.Clear();
        foreach (var p in _repository.AllProgress())
        {
            _records[p.templateId] = p;
            if (p.hasBeenCompleted) _completed.Add(p.templateId);
        }

    }

    public UniTask SaveAsync() => _repository.SaveAsync();

    public void MarkCompleted(string templateId)
    {
        if (!_records.TryGetValue(templateId, out var p))
        {
            p = new DrawingProgress { templateId = templateId, phase = DrawingPhase.Coloring };
        }

        p.hasBeenCompleted = true;
        p.completionCount += 1;
        _records[templateId] = p;
        _completed.Add(templateId);
    }

    public DrawingProgress? GetProgress(string templateId) =>
        _records.TryGetValue(templateId, out var p) ? p : (DrawingProgress?)null;

    public UniTask SaveProgressAsync(DrawingProgress progress) =>
        SaveProgressAsync(progress, thumbnailPng: null);

    public async UniTask SaveProgressAsync(DrawingProgress progress, byte[] thumbnailPng)
    {
        await _writeLock.WaitAsync();
        try
        {
            _records[progress.templateId] = progress;
            if (progress.hasBeenCompleted) _completed.Add(progress.templateId);

            await _repository.SaveProgressAsync(progress);
            if (thumbnailPng != null)
                await _repository.WriteThumbnailAsync(progress.templateId, thumbnailPng);
        }
        finally
        {
            _writeLock.Release();
        }
    }

    public async UniTask ClearProgressAsync(string templateId)
    {
        await _writeLock.WaitAsync();
        try
        {
            _records.Remove(templateId);
            _completed.Remove(templateId);
            await _repository.DeleteProgressAsync(templateId);
        }
        finally
        {
            _writeLock.Release();
        }
    }

    public bool IsCompleted(string templateId) => _completed.Contains(templateId);
    
    public UniTask<Texture2D> GetCachedThumbnailAsync(string templateId) =>
        _repository.LoadThumbnailAsync(templateId);
}