using Newtonsoft.Json;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace ITNexusAgent.Models;

public class AgentConfig
{
    private const string ProtectedPrefix = "dpapi:";

    [JsonIgnore]
    public string ServerUrl { get; set; } = "";

    // Im Speicher immer Klartext — nur auf der Platte (config.json) liegt der verschlüsselte Wert.
    [JsonIgnore]
    public string AgentKey { get; set; } = "";

    private class RawConfig
    {
        [JsonProperty("server_url")] public string ServerUrl { get; set; } = "";
        [JsonProperty("agent_key")] public string AgentKey { get; set; } = "";
    }

    public static AgentConfig Load(string path)
    {
        var json = File.ReadAllText(path);
        var raw = JsonConvert.DeserializeObject<RawConfig>(json)
            ?? throw new Exception("Ungültige config.json");

        return new AgentConfig
        {
            ServerUrl = raw.ServerUrl,
            AgentKey = Unprotect(raw.AgentKey),
        };
    }

    // Verschlüsselt den Key per Windows DPAPI (LocalMachine-Scope) bevor er auf die Platte geschrieben
    // wird — ein Klartext-Auslesen von config.json bringt einem Angreifer dann nichts mehr, da der Wert
    // nur vom SYSTEM-Konto auf genau diesem Rechner wieder entschlüsselt werden kann.
    public void Save(string path)
    {
        var raw = new RawConfig { ServerUrl = ServerUrl, AgentKey = Protect(AgentKey) };
        File.WriteAllText(path, JsonConvert.SerializeObject(raw, Formatting.Indented));
    }

    private static string Protect(string plaintext)
    {
        if (string.IsNullOrEmpty(plaintext)) return plaintext;
        var bytes = ProtectedData.Protect(Encoding.UTF8.GetBytes(plaintext), null, DataProtectionScope.LocalMachine);
        return ProtectedPrefix + Convert.ToBase64String(bytes);
    }

    // Erkennt das alte Klartext-Format (z.B. frisch aus dem Installer-Template) und lässt es unverändert
    // durch — wird beim nächsten Save() automatisch verschlüsselt persistiert.
    private static string Unprotect(string stored)
    {
        if (string.IsNullOrEmpty(stored) || !stored.StartsWith(ProtectedPrefix)) return stored;
        try
        {
            var bytes = ProtectedData.Unprotect(Convert.FromBase64String(stored[ProtectedPrefix.Length..]), null, DataProtectionScope.LocalMachine);
            return Encoding.UTF8.GetString(bytes);
        }
        catch
        {
            return stored; // Korrupt/falsche Maschine → unverändert zurückgeben statt Crash
        }
    }
}
