using System.Linq;
using Mlaumcherb.Client.Avalonia.зримое;
using Mlaumcherb.Client.Avalonia.классы;
using Mlaumcherb.Client.Avalonia.холопы;

namespace Mlaumcherb.Client.Avalonia.сеть.TaskFactories;

public class MyModpackV2DownloadTaskFactory : INetworkTaskFactory
{
    private readonly GameVersionDescriptor _descriptor;
    private IOPath _modpackDescriptorPath;
    private IOPath _versionDir;
    private MyModpackV2? _modpack;
    // relative, absolute
    private List<MyModpackV2.FileCheckResult> _filesToDownload = new();

    public MyModpackV2DownloadTaskFactory(GameVersionDescriptor descriptor)
    {
        _descriptor = descriptor;
        _modpackDescriptorPath = PathHelper.GetModpackDescriptorPath(_descriptor.id);
        _versionDir = PathHelper.GetVersionDir(_descriptor.id);
    }
    
    public async Task<NetworkTask?> CreateAsync(bool checkHashes)
    {
        if(_descriptor.modpack is null)
            throw new ArgumentNullException(nameof(_descriptor.modpack));
        
        (_modpack, bool didDownloadModpackDescriptor) = await NetworkHelper.ReadOrDownloadAndDeserialize<MyModpackV2>(
            _modpackDescriptorPath,
            _descriptor.modpack.artifact.url, 
            _descriptor.modpack.artifact.sha1,
            checkHashes);
        if (_modpack.format_version != _descriptor.modpack.format_version)
            throw new Exception($"Modpack.format_version mismatches descriptor.modpack.version: " +
                                $"{_modpack.format_version} != {_descriptor.modpack.format_version}");
        
        NetworkTask? networkTask = null;
        _filesToDownload = _modpack.CheckFiles(_versionDir, checkHashes, didDownloadModpackDescriptor);
        if(_filesToDownload.Count > 0)
        {
            networkTask = new NetworkTask(
                $"modpack '{_modpack.name}'",
                _filesToDownload.Sum(f => f.props.artifact.size),
                Download
            );
        }

        return networkTask;
    }

    private async Task Download(NetworkProgressReporter pr, CancellationToken ct)
    {
        LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"started downloading modpack '{_modpack!.name}'");

        ParallelOptions opt = new()
        {
            MaxDegreeOfParallelism = LauncherApp.Config.max_parallel_downloads,
            CancellationToken = ct
        };
        await Parallel.ForEachAsync(_filesToDownload, opt, async (f, _ct) =>
        {
            LauncherApp.Logger.LogDebug(nameof(NetworkHelper), $"downloading file '{f.relativePath}'");
            if(string.IsNullOrEmpty(f.props.artifact.url))
                throw new Exception($"file '{f.relativePath}' doesn't have a url to download");
            await NetworkHelper.DownloadFile(f.props.artifact.url, f.absolutePath, _ct, pr.AddBytesCount);
        });
        
        LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"finished downloading modpack '{_modpack.name}'");
    }
}