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

namespace Lentia.Core.Game;

public class Arguments {
    [JsonPropertyName("game")]
    public List<JsonElement>? Game { get; set; }

    [JsonPropertyName("jvm")]
    public List<JsonElement>? Jvm { get; set; }
}

public class ConditionalArgument {
    [JsonPropertyName("rules")]
    public List<Rule>? Rules { get; set; }

    [JsonPropertyName("value")]
    public JsonElement Value { get; set; }
}

public class MinecraftVersion {
    [JsonPropertyName("id")]
    public string? Id { get; set; }

    [JsonPropertyName("arguments")]
    public Arguments? Arguments { get; set; }

    [JsonPropertyName("assetIndex")]
    public AssetIndexInfo? AssetIndex { get; set; }

    [JsonPropertyName("downloads")]
    public Dictionary<string, DownloadInfo>? Downloads { get; set; }

    [JsonPropertyName("libraries")]
    public List<Library>? Libraries { get; set; }

    [JsonPropertyName("mainClass")]
    public string? MainClass { get; set; }

    [JsonPropertyName("type")]
    public string? Type { get; set; }

    [JsonPropertyName("logging")]
    public LoggingInfo? Logging { get; set; }

    [JsonPropertyName("javaVersion")]
    public JavaVersionInfo? JavaVersion { get; set; }

    [JsonPropertyName("minecraftArguments")]
    public string? MinecraftArguments { get; set; }
}

public class AssetIndexInfo {
    [JsonPropertyName("id")]
    public string? Id { get; set; }

    [JsonPropertyName("sha1")]
    public string? Sha1 { get; set; }

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

    [JsonPropertyName("totalSize")]
    public long TotalSize { get; set; }

    [JsonPropertyName("url")]
    public string? Url { get; set; }
}

public class Library {
    [JsonPropertyName("downloads")]
    public LibraryDownloads? Downloads { get; set; }

    [JsonPropertyName("name")]
    public string? Name { get; set; }

    [JsonPropertyName("rules")]
    public List<Rule>? Rules { get; set; }

    [JsonPropertyName("natives")]
    public Dictionary<string, string>? Natives { get; set; }
}

public class LibraryDownloads {
    [JsonPropertyName("artifact")]
    public DownloadInfo? Artifact { get; set; }

    [JsonPropertyName("classifiers")]
    public Dictionary<string, DownloadInfo>? Classifiers { get; set; }
}

public class DownloadInfo {
    [JsonPropertyName("id")]
    public string? Id { get; set; }

    [JsonPropertyName("sha1")]
    public string? Sha1 { get; set; }

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

    [JsonPropertyName("url")]
    public string? Url { get; set; }

    [JsonPropertyName("path")]
    public string? Path { get; set; }
}

public class Rule {
    [JsonPropertyName("action")]
    public string? Action { get; set; }

    [JsonPropertyName("os")]
    public OsRestriction? Os { get; set; }
}

public class OsRestriction {
    [JsonPropertyName("name")]
    public string? Name { get; set; }

    [JsonPropertyName("version")]
    public string? Version { get; set; }
}

public class VersionManifestV2
{
    [JsonPropertyName("latest")]
    public LatestVersion? Latest { get; set; }

    [JsonPropertyName("versions")]
    public List<VersionEntry>? Versions { get; set; }
}

public class LatestVersion
{
    [JsonPropertyName("release")]
    public string? Release { get; set; }

    [JsonPropertyName("snapshot")]
    public string? Snapshot { get; set; }
}

public class VersionEntry
{
    [JsonPropertyName("id")]
    public string? Id { get; set; }

    [JsonPropertyName("type")]
    public string? Type { get; set; }

    [JsonPropertyName("url")]
    public string? Url { get; set; }

    [JsonPropertyName("time")]
    public DateTime Time { get; set; }

    [JsonPropertyName("releaseTime")]
    public DateTime ReleaseTime { get; set; }

    [JsonPropertyName("sha1")]
    public string? Sha1 { get; set; }

    [JsonPropertyName("complianceLevel")]
    public int ComplianceLevel { get; set; }
}

public class LoggingInfo {
    [JsonPropertyName("client")]
    public LoggingClient? Client { get; set; }
}

public class LoggingClient {

    [JsonPropertyName("argument")]
    public string? Argument { get; set; }

    [JsonPropertyName("file")]
    public DownloadInfo? File { get; set; }

    [JsonPropertyName("type")]
    public string? Type { get; set; }
}

public class JavaVersionInfo {
    [JsonPropertyName("component")]
    public string? Component { get; set; }

    [JsonPropertyName("majorVersion")]
    public int MajorVersion { get; set; }
}

public static class VersionsHelper {

    public static async Task<string> GetVersionUrlAsync(string targetVersion) {
        var response = await HttpHelper.FetchAsync("https://piston-meta.mojang.com/mc/game/version_manifest_v2.json", HttpMethod.Get);
        
        var manifest = await response.Content.ReadFromJsonAsync<VersionManifestV2>();
        var versionEntry = manifest?.Versions?.FirstOrDefault(v => v.Id == targetVersion);
        

        return versionEntry?.Url ?? throw new Exception("Version introuvable dans le manifest Mojang.");
    }

    public static async Task<MinecraftVersion> GetVersionDetailsAsync(string versionUrl) {
        var response = await HttpHelper.FetchAsync(versionUrl, HttpMethod.Get);
        
        if (response.IsSuccessStatusCode) {
            string jsonResponse = await response.Content.ReadAsStringAsync();
            var version = JsonSerializer.Deserialize<MinecraftVersion>(jsonResponse, LauncherConstants._jsonOptions);
            
            return version ?? throw new Exception("Impossible de lire les détails de la version.");
        } else {
            throw new Exception($"Erreur lors de la récupération des détails : {response.StatusCode}");
        }
    }

    public static async Task DownloadClientJar(MinecraftVersion version, string root) {
        string jarVersionPath = Path.Combine(root, "versions", version.Id!, $"{version.Id}.jar");
        try {
            bool needsDownload = !File.Exists(jarVersionPath);

            if (!needsDownload) {
                var fileInfo = new FileInfo(jarVersionPath);
                long expectedSize = version.Downloads!["client"].Size;
                if (fileInfo.Length != expectedSize) {
                    needsDownload = true;
                }
            }

            if (needsDownload) {
                await FileHelper.DownloadFileAsync(version.Downloads!["client"].Url!, jarVersionPath);
            }
        } catch (Exception) {
            throw;
        }
    }

    public static async Task DownloadLoggingConfig(MinecraftVersion version, string root) {
        if (version.Logging?.Client?.File == null) return;

        var fileInfo = version.Logging.Client.File;
        string logConfigDir = Path.Combine(root, "assets", "log_configs");
        string destinationPath = Path.Combine(logConfigDir, fileInfo.Id ?? "client-log4j2.xml");

        if (File.Exists(destinationPath) && new FileInfo(destinationPath).Length == fileInfo.Size) {
            return; 
        }

        await FileHelper.DownloadFileAsync(fileInfo.Url!, destinationPath);
    }
}