// PRE-GENERATED (design session). DPAPI-encrypted secret store (NEVER plaintext).
// Requires NuGet: System.Security.Cryptography.ProtectedData (added in .csproj).
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using DansoriEQ.Core.Security;

namespace DansoriEQ.App.Security;

public sealed class DpapiSecretStore : ISecretStore
{
    private static readonly byte[] Entropy = Encoding.UTF8.GetBytes("DansoriEQ.secrets.v1");
    private readonly string _path;

    public DpapiSecretStore(string? filePath = null)
    {
        var dir = Path.GetDirectoryName(filePath)
                  ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "DansoriEQ");
        Directory.CreateDirectory(dir);
        _path = filePath ?? Path.Combine(dir, "secrets.dat");
    }

    public bool Has(string key)
        => Read().TryGetValue(key, out var v) && !string.IsNullOrEmpty(v);

    public void Save(string key, string secret)
    {
        var map = Read();
        var enc = ProtectedData.Protect(Encoding.UTF8.GetBytes(secret), Entropy, DataProtectionScope.CurrentUser);
        map[key] = Convert.ToBase64String(enc);   // stored value is ciphertext, not the key
        Write(map);
    }

    public string? Load(string key)
    {
        if (!Read().TryGetValue(key, out var b64) || string.IsNullOrEmpty(b64)) return null;
        try
        {
            var dec = ProtectedData.Unprotect(Convert.FromBase64String(b64), Entropy, DataProtectionScope.CurrentUser);
            return Encoding.UTF8.GetString(dec);
        }
        catch { return null; }
    }

    public void Delete(string key)
    {
        var map = Read();
        if (map.Remove(key)) Write(map);
    }

    private Dictionary<string, string> Read()
    {
        try
        {
            return File.Exists(_path)
                ? JsonSerializer.Deserialize<Dictionary<string, string>>(File.ReadAllText(_path)) ?? new()
                : new();
        }
        catch { return new(); }
    }

    private void Write(Dictionary<string, string> map)
        => File.WriteAllText(_path, JsonSerializer.Serialize(map));
}
