using NSec.Cryptography;

if (args.Length == 0)
{
    PrintUsage();
    return 0;
}

try
{
    return args[0] switch
    {
        "generate-key"  => GenerateKey(args),
        "export-pubkey" => ExportPubkey(args),
        "sign"          => Sign(args),
        "verify"        => Verify(args),
        _               => UnknownCommand()
    };
}
catch (Exception ex)
{
    Console.Error.WriteLine($"Error: {ex.Message}");
    return 1;
}

static int UnknownCommand()
{
    Console.Error.WriteLine("Unknown command.");
    PrintUsage();
    return 1;
}

static int GenerateKey(string[] args)
{
    string outPath = RequireArg(args, "--out");
    if (File.Exists(outPath))
        throw new InvalidOperationException($"{outPath} already exists. Refusing to overwrite a keypair.");

    var algorithm = SignatureAlgorithm.Ed25519;
    using var key = Key.Create(algorithm, new KeyCreationParameters
    {
        ExportPolicy = KeyExportPolicies.AllowPlaintextExport
    });
    byte[] priv = key.Export(KeyBlobFormat.RawPrivateKey);
    byte[] pub  = key.PublicKey.Export(KeyBlobFormat.RawPublicKey);

    File.WriteAllText(outPath, $"{Convert.ToBase64String(priv)}\n{Convert.ToBase64String(pub)}\n");
    Console.WriteLine($"Wrote keypair to {outPath}");
    Console.WriteLine("Protect this file. Losing it means you cannot ship updates; leaking it means anyone can.");
    return 0;
}

static int ExportPubkey(string[] args)
{
    string keyPath = RequireArg(args, "--key");
    (_, byte[] pub) = LoadKeypair(keyPath);

    string literal = string.Join(", ", pub.Select(b => $"0x{b:x2}"));
    Console.WriteLine("// Paste into src/Flo.Installer/TrustedPublicKey.cs");
    Console.WriteLine($"public static readonly byte[] Bytes = new byte[] {{ {literal} }};");
    return 0;
}

static int Sign(string[] args)
{
    string manifestPath = RequireArg(args, "--manifest");
    string keyPath = RequireArg(args, "--key");
    string outPath = RequireArg(args, "--out");

    (byte[] priv, _) = LoadKeypair(keyPath);
    var algorithm = SignatureAlgorithm.Ed25519;
    using var signingKey = Key.Import(algorithm, priv, KeyBlobFormat.RawPrivateKey);
    byte[] manifestBytes = File.ReadAllBytes(manifestPath);
    byte[] signature = algorithm.Sign(signingKey, manifestBytes);

    File.WriteAllText(outPath, Convert.ToBase64String(signature));
    Console.WriteLine($"Signed: {manifestPath} -> {outPath}");
    return 0;
}

static int Verify(string[] args)
{
    string manifestPath = RequireArg(args, "--manifest");
    string sigPath = RequireArg(args, "--sig");
    string keyPath = RequireArg(args, "--key");

    (_, byte[] pub) = LoadKeypair(keyPath);
    var algorithm = SignatureAlgorithm.Ed25519;
    var pubKey = NSec.Cryptography.PublicKey.Import(algorithm, pub, KeyBlobFormat.RawPublicKey);
    byte[] manifestBytes = File.ReadAllBytes(manifestPath);
    byte[] signature = Convert.FromBase64String(File.ReadAllText(sigPath).Trim());

    bool ok = algorithm.Verify(pubKey, manifestBytes, signature);
    Console.WriteLine(ok ? "OK: signature valid." : "FAIL: signature INVALID.");
    return ok ? 0 : 2;
}

static (byte[] priv, byte[] pub) LoadKeypair(string path)
{
    string[] lines = File.ReadAllLines(path);
    if (lines.Length < 2)
        throw new InvalidOperationException($"Malformed keypair file: {path}");
    return (Convert.FromBase64String(lines[0]), Convert.FromBase64String(lines[1]));
}

static string RequireArg(string[] args, string name)
{
    int i = Array.IndexOf(args, name);
    if (i < 0 || i + 1 >= args.Length)
        throw new ArgumentException($"{name} <value> is required.");
    return args[i + 1];
}

static void PrintUsage()
{
    Console.WriteLine("Flo.Manifest.Tool  (release-side signing helper)");
    Console.WriteLine();
    Console.WriteLine("Commands:");
    Console.WriteLine("  generate-key   --out <keypair-file>");
    Console.WriteLine("  export-pubkey  --key <keypair-file>");
    Console.WriteLine("  sign           --manifest <path> --key <keypair-file> --out <sig-file>");
    Console.WriteLine("  verify         --manifest <path> --sig <sig-file> --key <keypair-file>");
}
