using System.Security.Cryptography;
using System.Net.Http.Json;
using BrikInstaller.Schemas;

namespace BrikInstaller.Services;

public static class GenericFilesService {
    private static readonly HttpClient _httpClient = new();

    public static async Task SyncFilesAsync(string rootEndpoint, string apiUrl, string destinationDir) {
        Console.WriteLine(rootEndpoint);
        try {
            var index = await _httpClient.GetFromJsonAsync<BrikFilesIndex>(apiUrl);
            if (index?.Root == null) return;

            var artifacts = index.Root.Select(r => r.Downloads.Artifact).ToList();
            await ProcessDownloadsAsync(rootEndpoint, artifacts, destinationDir);
        }
        catch (Exception ex) {
            Console.WriteLine($"[Sync Error] {ex.Message}");
        }
    }

    private static async Task ProcessDownloadsAsync(string rootEndpoint, List<GenericArtifact> artifacts, string baseDir) {
        var queue = artifacts.Where(a => !IsFileValid(Path.Combine(baseDir, a.Path), a)).ToList();

        if (queue.Count == 0) return;

        await Parallel.ForEachAsync(queue, new ParallelOptions { MaxDegreeOfParallelism = 4 }, async (artifact, token) => {
            string localPath = Path.Combine(baseDir, artifact.Path);
            
            try {
                await HttpHelper.DownloadFileAsync(rootEndpoint + artifact.Url, localPath);
                
                if (!IsFileValid(localPath, artifact)) {
                    Console.WriteLine($"[Validation Failed] {artifact.Path}");
                }
            }
            catch (Exception ex) {
                Console.WriteLine($"[Download Error] {artifact.Path}: {ex.Message}");
            }
        });
    }

    public static bool IsFileValid(string filePath, GenericArtifact expected) {
        if (!File.Exists(filePath)) return false;

        var info = new FileInfo(filePath);
        if (info.Length != expected.Size) return false;

        using var stream = File.OpenRead(filePath);
        byte[] hashBytes = SHA1.HashData(stream);
        string hash = BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
        
        return hash == expected.Sha1.ToLowerInvariant();
    }
}