using System;
using System.IO;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace ModpackLauncher.Models;

public sealed class LauncherConfig
{
    [JsonPropertyName("packName")]
    public string PackName { get; set; } = "Modpack";

    [JsonPropertyName("manifestUrl")]
    public string ManifestUrl { get; set; } = "";

    /// <summary>
    /// Subfolder name appended under the install location (sidecar exe folder
    /// by default, or the folder the user picked via "Change..."). Acts as
    /// a safety net so picking a generic location like "D:\" doesn't dump
    /// thousands of files at the drive root, and signals at a glance that
    /// this is the launcher's data, not the launcher itself.
    /// </summary>
    [JsonPropertyName("installDirName")]
    public string InstallDirName { get; set; } = "BrassAndSigilData";

    [JsonPropertyName("memoryMB")]
    public int MemoryMB { get; set; } = 8192;

    [JsonPropertyName("msalClientId")]
    public string MsalClientId { get; set; } = "";

    /// <summary>Optional HTTP Basic auth username for the manifest URL and mod file URLs.</summary>
    [JsonPropertyName("httpUsername")]
    public string? HttpUsername { get; set; }

    /// <summary>Optional HTTP Basic auth password (paired with HttpUsername).</summary>
    [JsonPropertyName("httpPassword")]
    public string? HttpPassword { get; set; }

    public static LauncherConfig Load()
    {
        // 1. External override beside the exe (dev convenience / per-deploy override)
        var sidecar = Path.Combine(AppContext.BaseDirectory, "launcher-config.json");
        if (File.Exists(sidecar))
        {
            return ParseSafe(File.ReadAllText(sidecar));
        }

        // 2. Embedded launcher-config.json (set at build time from local copy)
        var asm = typeof(LauncherConfig).Assembly;
        using (var stream = asm.GetManifestResourceStream("launcher-config.json"))
        {
            if (stream != null)
            {
                using var reader = new StreamReader(stream);
                return ParseSafe(reader.ReadToEnd());
            }
        }

        // 3. Fall back to embedded template (so fresh clones still run, with placeholders)
        using (var stream = asm.GetManifestResourceStream("launcher-config.template.json"))
        {
            if (stream != null)
            {
                using var reader = new StreamReader(stream);
                return ParseSafe(reader.ReadToEnd());
            }
        }

        return new LauncherConfig();
    }

    private static LauncherConfig ParseSafe(string json)
    {
        var opts = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
        return JsonSerializer.Deserialize<LauncherConfig>(json, opts) ?? new LauncherConfig();
    }

    /// <summary>
    /// Resolve the absolute install directory. The launcher behaves as a
    /// portable app: by default it installs alongside the exe in
    /// <c>&lt;exe-folder&gt;/&lt;InstallDirName&gt;/</c>. The user can override
    /// via the "Change..." picker, which stores the chosen *parent* folder
    /// in <c>InstallDirOverride</c>; we then append <see cref="InstallDirName"/>
    /// to it (same safety reasoning as the default).
    ///
    /// Smart-skip: if the parent path already ends in InstallDirName, we
    /// don't double up. Lets users re-pick their existing install folder
    /// (e.g. "D:\Games\BrassAndSigilData") without ending up at
    /// "D:\Games\BrassAndSigilData\BrassAndSigilData".
    /// </summary>
    public string GetInstallDir(string? overrideDir = null)
    {
        var parent = !string.IsNullOrWhiteSpace(overrideDir)
            ? overrideDir!
            : AppContext.BaseDirectory;

        var trimmed = parent.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
        if (string.Equals(Path.GetFileName(trimmed), InstallDirName, StringComparison.OrdinalIgnoreCase))
        {
            return trimmed;
        }
        return Path.Combine(parent, InstallDirName);
    }
}
