#ifndef LIGHTNING_COMMON_HSM_SECRET_H
#define LIGHTNING_COMMON_HSM_SECRET_H
#include "config.h"
#include <bitcoin/privkey.h>
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>
#include <sodium.h>
#include <sys/types.h>

/* Length constants for encrypted HSM secret files */
#define HS_HEADER_LEN crypto_secretstream_xchacha20poly1305_HEADERBYTES
#define HS_CIPHERTEXT_LEN \
	(sizeof(struct secret) + crypto_secretstream_xchacha20poly1305_ABYTES)
#define ENCRYPTED_HSM_SECRET_LEN (HS_HEADER_LEN + HS_CIPHERTEXT_LEN)

enum hsm_secret_type {
	HSM_SECRET_PLAIN = 0,               /* Legacy 32-byte format */
	HSM_SECRET_ENCRYPTED = 1,           /* Legacy 73-byte encrypted format */
	HSM_SECRET_MNEMONIC_NO_PASS = 2,    /* Mnemonic without passphrase */
	HSM_SECRET_MNEMONIC_WITH_PASS = 3,  /* Mnemonic with passphrase */
	HSM_SECRET_INVALID = 4,             /* When all else fails, blame the user */
};

enum hsm_secret_error {
	HSM_SECRET_OK = 0,
	HSM_SECRET_ERR_PASSPHRASE_REQUIRED,
	HSM_SECRET_ERR_PASSPHRASE_NOT_NEEDED,
	HSM_SECRET_ERR_WRONG_PASSPHRASE,
	HSM_SECRET_ERR_INVALID_MNEMONIC,
	HSM_SECRET_ERR_ENCRYPTION_FAILED,
	HSM_SECRET_ERR_SEED_DERIVATION_FAILED,
	HSM_SECRET_ERR_INVALID_FORMAT,
	HSM_SECRET_ERR_TERMINAL,
};

/**
 * Represents the content of the hsm_secret file, either a raw seed or a mnemonic.
 */
struct hsm_secret {
	enum hsm_secret_type type;
	const u8 *secret_data;          /* Variable length: 32 bytes (legacy) or 64 bytes (mnemonic) */
	const char *mnemonic;           /* NULL if not derived from mnemonic */
};


/**
 * Check if this HSM secret is mnemonic-based (64-byte seed).
 * Returns true for mnemonic-derived secrets, false for legacy 32-byte secrets.
 */
bool is_mnemonic_secret(size_t secret_len);

/**
 * Check if we should use BIP86 derivation for this HSM secret.
 * BIP86 was introduced alongside mnemonic support, so they're available together.
 * Returns true if mnemonic-based secret is available, false otherwise.
 */
bool use_bip86_derivation(size_t secret_len);

/**
 * Checks whether the hsm_secret data requires a passphrase to decrypt.
 * Handles legacy, encrypted, and mnemonic-based formats.
 */
bool hsm_secret_needs_passphrase(const u8 *hsm_secret, size_t len);

/**
 * Parse and decrypt an hsm_secret file.
 *
 * @ctx - a tal context
 * @hsm_secret - raw file contents
 * @len - length of file
 * @passphrase - passphrase, or NULL if not needed
 * @err - pointer to set error code on failure
 *
 * Returns parsed `struct hsm_secret` or NULL on error.
 */
struct hsm_secret *extract_hsm_secret(const tal_t *ctx,
				      const u8 *hsm_secret, size_t len,
				      const char *passphrase,
				      enum hsm_secret_error *err);


/**
 * get_encryption_key - Derive encryption key from passphrase using Argon2.
 * @ctx - tal context for allocation
 * @passphrase - the passphrase to derive from
 *
 * Returns derived encryption key, or NULL on error.
 * The returned key is memory-locked and has a destructor to clear it.
 */
struct secret *get_encryption_key(const tal_t *ctx, const char *passphrase);

/**
 * Encrypt a given hsm_secret using a provided encryption key.
 * @encryption_key - derived from passphrase (via Argon2)
 * @hsm_secret - plaintext secret to encrypt
 * @output - output buffer for encrypted data (must be ENCRYPTED_HSM_SECRET_LEN bytes)
 *
 * Returns true on success.
 */
bool encrypt_legacy_hsm_secret(const struct secret *encryption_key,
			       const struct secret *hsm_secret,
			       u8 *output);

/**
 * Reads a passphrase from stdin, disabling terminal echo.
 * Returns a newly allocated string on success, NULL on error.
 * @ctx - tal context for allocation
 * @err - on failure, this will be set to the error code
 *
 * Returns allocated passphrase or NULL on error.
 */
const char *read_stdin_pass(const tal_t *ctx, enum hsm_secret_error *err);

/**
 * Convert error code to human-readable string.
 * @err - the error code to convert
 *
 * Returns a string describing the error.
 */
const char *hsm_secret_error_str(enum hsm_secret_error err);

/**
 * Detect the type of hsm_secret based on its content and length.
 * @hsm_secret - raw file contents
 * @len - length of file
 *
 * Returns the detected type.
 */
enum hsm_secret_type detect_hsm_secret_type(const u8 *hsm_secret, size_t len);

/**
 * Check a BIP39 mnemonic is valid.
 * @mnemonic - 12 words, single-space separated, nul terminate.
 *
 * Returns HSM_SECRET_ERR_INVALID_MNEMONIC or HSM_SECRET_OK.
 */
enum hsm_secret_error validate_mnemonic(const char *mnemonic);

/**
 * Reads a BIP39 mnemonic from stdin with validation.
 * Returns a newly allocated string on success, NULL on error.
 * @ctx - tal context for allocation
 * @err - optional pointer to set error code on failure
 *
 * Returns tal-allocated mnemonic string or NULL on error.
 */
const char *read_stdin_mnemonic(const tal_t *ctx, enum hsm_secret_error *err);

/**
 * Derive seed hash from mnemonic + passphrase.
 * @mnemonic - the BIP39 mnemonic
 * @passphrase - the passphrase (can be NULL)
 * @seed_hash - output parameter for the derived seed hash
 *
 * Returns true on success, false on failure.
 */
bool derive_seed_hash(const char *mnemonic, const char *passphrase, struct sha256 *seed_hash);

/**
 * Check if hsm_secret file is encrypted (legacy format only).
 * @path - path to the hsm_secret file
 *
 * Returns 1 if encrypted, 0 if not encrypted, -1 on error.
 */
int is_legacy_hsm_secret_encrypted(const char *path);

/**
 * Convert hsm_secret_type enum to human-readable string.
 * @type - the hsm_secret_type to convert
 *
 * Returns a string describing the type.
 */
const char *format_type_name(enum hsm_secret_type type);

/**
 * Derive encryption key from passphrase using Argon2.
 * @ctx - tal context for allocation
 * @passphrase - the passphrase to derive from
 *
 * Returns derived encryption key, or NULL on error.
 * The returned key is memory-locked and has a destructor to clear it.
 */
struct secret *get_encryption_key(const tal_t *ctx, const char *passphrase);

#endif /* LIGHTNING_COMMON_HSM_SECRET_H */
