// ObsidianDragon Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3

#pragma once

#include <string>
#include <vector>
#include <cstdint>

namespace dragonx {
namespace util {

/**
 * @brief PIN-encrypted passphrase vault
 *
 * Stores the wallet passphrase encrypted with a PIN-derived key using
 * libsodium's Argon2id (key derivation) + XSalsa20-Poly1305 (AEAD).
 *
 * File format (vault.dat):
 *   [1 byte]  version (0x01)
 *   [16 bytes] Argon2id salt
 *   [24 bytes] XSalsa20 nonce
 *   [N bytes]  ciphertext (passphrase + 16-byte Poly1305 tag)
 *
 * The PIN is 4-8 digits. Argon2id uses moderate ops/mem limits
 * to resist brute-force on the small PIN space while keeping
 * unlock time under ~1 second.
 */
class SecureVault {
public:
    // `walletFile` scopes the vault to a specific wallet.dat so one wallet's PIN passphrase is never
    // offered for another. The default wallet ("wallet.dat" / empty) keeps the legacy global vault.dat
    // path for backward compatibility; other wallets get their own vault-<scope>.dat.
    explicit SecureVault(const std::string& walletFile = "");
    ~SecureVault();

    // Re-scope to a different wallet (called when the active wallet changes).
    void setWalletScope(const std::string& walletFile);

    /**
     * @brief Check if a vault file exists on disk
     */
    bool hasVault() const;

    /**
     * @brief Encrypt passphrase with PIN and save to vault.dat
     * @param pin      The user's PIN (4-8 digits)
     * @param passphrase  The wallet passphrase to protect
     * @return true on success
     */
    bool store(const std::string& pin, const std::string& passphrase);

    /**
     * @brief Decrypt passphrase from vault using PIN
     * @param pin      The user's PIN
     * @param[out] passphrase  The recovered passphrase
     * @return true if PIN was correct and decryption succeeded
     */
    bool retrieve(const std::string& pin, std::string& passphrase) const;

    /**
     * @brief Change the PIN (re-encrypt with new PIN)
     * @param oldPin  Current PIN
     * @param newPin  New PIN
     * @return true if old PIN was valid and re-encryption succeeded
     */
    bool changePin(const std::string& oldPin, const std::string& newPin);

    /**
     * @brief Remove the vault file
     * @return true if deleted or didn't exist
     */
    bool removeVault();

    /**
     * @brief Validate PIN format (4-8 digits)
     */
    static bool isValidPin(const std::string& pin);

    /**
     * @brief Securely zero memory
     */
    static void secureZero(void* ptr, size_t len);

    /**
     * @brief Get this vault's file path (scoped to its wallet)
     */
    std::string getVaultPath() const;

private:
    // Derive a 32-byte key from PIN + salt using Argon2id
    bool deriveKey(const std::string& pin,
                   const uint8_t* salt, size_t saltLen,
                   uint8_t* key, size_t keyLen) const;

    std::string scope_;   // "" = default/legacy wallet (vault.dat); else a sanitized wallet-file tag
};

} // namespace util
} // namespace dragonx
