using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Data.Dynamic.Features.Progression;
using Darkmatter.Libs.PlayerPrefs;
using UnityEngine;

namespace Darkmatter.Features.Progression.Systems;

public sealed class ProgressionRepository
{
    private const string ThumbnailsFolder = "thumbnails";

    private readonly Dictionary<string, DrawingProgress> _records = new();

    public IEnumerable<DrawingProgress> AllProgress() => _records.Values;

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

    public UniTask LoadAsync()
    {
        _records.Clear();

        var json = ProtectedPlayerPrefs.GetString(PlayerPrefsKeys.Progression, "");
        if (string.IsNullOrEmpty(json)) return UniTask.CompletedTask;

        ProgressionRootDto root;
        try
        {
            root = JsonUtility.FromJson<ProgressionRootDto>(json);
        }
        catch (Exception e)
        {
            Debug.LogError($"[Progression] Failed to parse saved root: {e}");
            return UniTask.CompletedTask;
        }

        if (root.records != null)
        {
            foreach (var rec in root.records)
                if (!string.IsNullOrEmpty(rec.templateId))
                    _records[rec.templateId] = rec;
        }

        return UniTask.CompletedTask;
    }

    public UniTask SaveAsync()
    {
        FlushRoot();
        return UniTask.CompletedTask;
    }

    public UniTask SaveProgressAsync(DrawingProgress p)
    {
        if (string.IsNullOrEmpty(p.templateId))
            throw new ArgumentException("DrawingProgress.templateId must be set.");
        _records[p.templateId] = p;
        FlushRoot();
        return UniTask.CompletedTask;
    }

    public UniTask DeleteProgressAsync(string templateId)
    {
        if (string.IsNullOrEmpty(templateId)) return UniTask.CompletedTask;
        _records.Remove(templateId);
        FlushRoot();
        TryDeleteThumbnailFile(templateId);
        return UniTask.CompletedTask;
    }

    public async UniTask WriteThumbnailAsync(string templateId, byte[] png)
    {
        if (string.IsNullOrEmpty(templateId) || png == null || png.Length == 0) return;

        Directory.CreateDirectory(ThumbnailDirectory());
        var path = ThumbnailPath(templateId);
        var tmp = path + ".tmp";

        await UniTask.RunOnThreadPool(() =>
        {
            File.WriteAllBytes(tmp, png);
            if (File.Exists(path)) File.Delete(path);
            File.Move(tmp, path);
        });
    }

    public async UniTask<Texture2D> LoadThumbnailAsync(string templateId)
    {
        if (string.IsNullOrEmpty(templateId)) return null;
        var path = ThumbnailPath(templateId);
        if (!File.Exists(path)) return null;

        byte[] bytes;
        try
        {
            bytes = await UniTask.RunOnThreadPool(() => File.ReadAllBytes(path));
        }
        catch (Exception e)
        {
            Debug.LogWarning($"[Progression] Failed reading thumbnail '{templateId}': {e.Message}");
            return null;
        }

        await UniTask.SwitchToMainThread();
        var tex = new Texture2D(2, 2, TextureFormat.RGBA32, mipChain: false);
        if (!tex.LoadImage(bytes))
        {
            UnityEngine.Object.Destroy(tex);
            return null;
        }

        return tex;
    }

    private void FlushRoot()
    {
        var root = new ProgressionRootDto
        {
            records = _records.Values.ToList(),
        };
        var json = JsonUtility.ToJson(root);
        ProtectedPlayerPrefs.SetString(PlayerPrefsKeys.Progression, json);
        ProtectedPlayerPrefs.Save();
    }

    private static void TryDeleteThumbnailFile(string templateId)
    {
        try
        {
            var path = ThumbnailPath(templateId);
            if (File.Exists(path)) File.Delete(path);
        }
        catch (Exception e)
        {
            Debug.LogWarning($"[Progression] Failed deleting thumbnail '{templateId}': {e.Message}");
        }
    }

    private static string ThumbnailDirectory() =>
        Path.Combine(Application.persistentDataPath, ThumbnailsFolder);

    private static string ThumbnailPath(string templateId) =>
        Path.Combine(ThumbnailDirectory(), SafeFileName(templateId) + ".png");

    private static string SafeFileName(string templateId) =>
        templateId.Replace('/', '_').Replace('\\', '_');
}