using System.Text.Json;
using System.Text.Json.Serialization;
using Lentia.Core.Constants;
using Lentia.Core.Utils;

namespace Lentia.Core.Game;
public class AssetsIndex {
    [JsonPropertyName("objects")]
    public Dictionary<string, AssetObject>? Objects { get; set; }
}

public class AssetObject {
    [JsonPropertyName("hash")]
    public string? Hash { get; set; }

    [JsonPropertyName("size")]
    public long Size { get; set; }
}

public class AssetsHelper {
    
    public static string GetAssetLocalPath(string hash, string assetsDir) {
        string subFolder = hash.Substring(0, 2);
        return Path.Combine(assetsDir, subFolder, hash);
    }

    public static async Task<AssetsIndex> GetAssetsIndexAsync(string url) {        
        var response = await HttpHelper.FetchAsync(url, HttpMethod.Get);
        
        if (response.IsSuccessStatusCode) {
            string json = await response.Content.ReadAsStringAsync();
            var index = JsonSerializer.Deserialize<AssetsIndex>(json, LauncherConstants._jsonOptions);
            
            return index ?? throw new Exception("L'index des assets est vide ou invalide.");
        }
        
        throw new Exception($"Impossible de récupérer l'index des assets : {response.StatusCode}");
    }

    public static async Task DownloadAssets(AssetsIndex index, string rootDir) {
        string objectsDir = Path.Combine(rootDir, "assets", "objects");

        foreach (var entry in index.Objects!) {
            string hash = entry.Value.Hash!;
            long expectedSize = entry.Value.Size;
            string localPath = GetAssetLocalPath(hash, objectsDir);
            
            bool needsDownload = !File.Exists(localPath);

            if (!needsDownload) {
                var fileInfo = new FileInfo(localPath);
                if (fileInfo.Length != expectedSize) {
                    needsDownload = true;
                }
            }

            if (needsDownload) {
                string url = $"https://resources.download.minecraft.net/{hash.Substring(0, 2)}/{hash}";
                await FileHelper.DownloadFileAsync(url, localPath);
            }
        }
    }
    
    public static async Task DownloadAssetsParallel(AssetsIndex index, string rootDir) {
        string objectsDir = Path.Combine(rootDir, "assets", "objects");
        
        var uniqueAssets = index.Objects!
            .GroupBy(x => x.Value.Hash)
            .Select(g => g.First().Value)
            .ToList();

        var options = new ParallelOptions { MaxDegreeOfParallelism = 8 };

        await Parallel.ForEachAsync(uniqueAssets, options, async (asset, token) => {
            string hash = asset.Hash!;
            long expectedSize = asset.Size;
            string localPath = GetAssetLocalPath(hash, objectsDir);

            if (File.Exists(localPath)) {
                if (new FileInfo(localPath).Length == expectedSize) return;
            }

            string prefix = hash.Substring(0, 2);
            string url = $"https://resources.download.minecraft.net/{prefix}/{hash}";
            
            try {
                await FileHelper.DownloadFileAsync(url, localPath);
            } catch (Exception ex) {
                Console.WriteLine(url);
                Console.WriteLine($"Échec : {hash} - {ex.Message}");
            }
        });
    }

}