using DTLib.Extensions;
using Mlaumcherb.Client.Avalonia.холопы;

namespace Mlaumcherb.Client.Avalonia.классы;

public class Libraries
{
    private static readonly string[] enabled_features = [];
    
    public record JarLib(string name, IOPath jarFilePath, Artifact? artifact);
    public record NativeLib(string name, IOPath jarFilePath, Artifact? artifact, Extract? extractionOptions) 
        : JarLib(name, jarFilePath, artifact);
    
    public IReadOnlyCollection<JarLib> Libs { get; }

    public static IOPath GetPathFromMavenName(string mavenName, string ext = "jar")
    {
        int sep_0 = mavenName.IndexOf(':');
        if (sep_0 == -1)
            throw new ArgumentException($"Invalid maven name: {mavenName}");
        int sep_1 = mavenName.IndexOf(':', sep_0 + 1);
        if (sep_1 == -1)
            throw new ArgumentException($"Invalid maven name: {mavenName}");
        var package = mavenName.Substring(0, sep_0).Replace('.', '/');
        var artifact = mavenName.Substring(sep_0 + 1, sep_1 - sep_0 - 1);
        var version = mavenName.Substring(sep_1 + 1);
        string file_name = $"{artifact}-{version}.{ext}";
        return Path.Concat(PathHelper.GetLibrariesDir(), package, artifact, version, file_name);
    }
    
    private static IOPath GetPathFromArtifact(Artifact artifact)
    {
        string relativePath;
        if (!string.IsNullOrEmpty(artifact.path))
            relativePath = artifact.path;
        else if (!string.IsNullOrEmpty(artifact.url))
            relativePath = artifact.url.AsSpan().After("://").After('/').ToString();
        else throw new ArgumentException("Artifact must have a path or url");

        return Path.Concat(PathHelper.GetLibrariesDir(), relativePath);
    }
    
    public Libraries(GameVersionDescriptor descriptor)
    {
        List<JarLib> libs = new();
        HashSet<string> libHashes = new();
        
        foreach (var l in descriptor.libraries)
        {
            if (l.rules != null && !Rules.Check(l.rules, enabled_features))
                continue;

            if (l.natives != null)
            {
                string? nativesKey;
                if (OperatingSystem.IsWindows())
                    nativesKey = l.natives.windows;
                else if (OperatingSystem.IsLinux())
                    nativesKey = l.natives.linux;
                else if (OperatingSystem.IsMacOS())
                    nativesKey = l.natives.osx;
                else throw new PlatformNotSupportedException();
                if(nativesKey is null)
                    throw new Exception($"nativesKey for '{l.name}' is null");
                
                // example: "natives-windows-${arch}"
                if (nativesKey.Contains('$'))
                {
                    var span = nativesKey.AsSpan();
                    nativesKey = span.After("${").Before('}') switch
                    {
                        "arch" => span.Before("${").ToString() + PlatformHelper.GetArchOld(),
                        _ => throw new Exception($"unknown placeholder in {nativesKey}")
                    };
                }
                
                Artifact artifact = null!;
                if(l.downloads?.classifiers != null && !l.downloads.classifiers.TryGetValue(nativesKey, out artifact!))
                    throw new Exception($"can't find artifact for '{l.name}' with nativesKey '{nativesKey}'");
                
                // skipping duplicates (WHO THE HELL CREATES THIS DISCRIPTORS AAAAAAAAA)
                if(!libHashes.Add(artifact.sha1))
                    continue;
                
                libs.Add(new NativeLib(l.name, GetPathFromArtifact(artifact), artifact, l.extract));
            }
            else
            {
                Artifact? artifact = l.downloads?.artifact;
                if (artifact is null)
                {
                    libs.Add(new JarLib(l.name, GetPathFromMavenName(l.name), artifact));
                }
                else
                {
                    // skipping duplicates
                    if (!libHashes.Add(artifact.sha1))
                        continue;

                    libs.Add(new JarLib(l.name, GetPathFromArtifact(artifact), artifact));
                }
            }
        }

        Libs = libs;
    }
}