/**
 * Synor Crypto SDK for C++
 *
 * Quantum-resistant cryptographic primitives for the Synor blockchain.
 *
 * Example:
 * ```cpp
 * #include <synor/crypto.hpp>
 *
 * int main() {
 *     synor::crypto::Config config{"your-api-key"};
 *     synor::crypto::SynorCrypto crypto{config};
 *
 *     // Generate a mnemonic
 *     auto mnemonic = crypto.mnemonic().generate(24).get();
 *     std::cout << "Backup words: " << mnemonic.phrase << std::endl;
 *
 *     // Create keypair from mnemonic
 *     auto keypair = crypto.keypairs().from_mnemonic(mnemonic.phrase, "").get();
 *     auto address = keypair.get_address(synor::crypto::Network::Mainnet);
 *
 *     // Sign a message
 *     auto signature = crypto.signing().sign(keypair, "Hello!").get();
 * }
 * ```
 */

#ifndef SYNOR_CRYPTO_HPP
#define SYNOR_CRYPTO_HPP

#include <string>
#include <vector>
#include <map>
#include <memory>
#include <future>
#include <optional>
#include <stdexcept>
#include <cstdint>

namespace synor {
namespace crypto {

// ============================================================================
// Constants
// ============================================================================

constexpr int ED25519_PUBLIC_KEY_SIZE = 32;
constexpr int ED25519_SECRET_KEY_SIZE = 32;
constexpr int ED25519_SIGNATURE_SIZE = 64;
constexpr int DILITHIUM3_PUBLIC_KEY_SIZE = 1952;
constexpr int DILITHIUM3_SIGNATURE_SIZE = 3293;
constexpr int HYBRID_SIGNATURE_SIZE = 64 + 3293;
constexpr int COIN_TYPE = 0x5359;
constexpr int MIN_PBKDF2_ITERATIONS = 10000;
constexpr int MIN_SALT_LENGTH = 8;
constexpr const char* DEFAULT_ENDPOINT = "https://crypto.synor.io/v1";

// ============================================================================
// Enumerations
// ============================================================================

enum class Network {
    Mainnet,
    Testnet,
    Devnet
};

inline std::string to_string(Network n) {
    switch (n) {
        case Network::Mainnet: return "mainnet";
        case Network::Testnet: return "testnet";
        case Network::Devnet: return "devnet";
    }
    return "mainnet";
}

inline Network network_from_string(const std::string& s) {
    if (s == "testnet") return Network::Testnet;
    if (s == "devnet") return Network::Devnet;
    return Network::Mainnet;
}

enum class FalconVariant {
    Falcon512,
    Falcon1024
};

inline std::string to_string(FalconVariant v) {
    switch (v) {
        case FalconVariant::Falcon512: return "falcon512";
        case FalconVariant::Falcon1024: return "falcon1024";
    }
    return "falcon512";
}

inline int signature_size(FalconVariant v) {
    return v == FalconVariant::Falcon512 ? 690 : 1330;
}

inline int public_key_size(FalconVariant v) {
    return v == FalconVariant::Falcon512 ? 897 : 1793;
}

inline int security_level(FalconVariant v) {
    return v == FalconVariant::Falcon512 ? 128 : 256;
}

enum class SphincsVariant {
    Shake128s,
    Shake192s,
    Shake256s
};

inline std::string to_string(SphincsVariant v) {
    switch (v) {
        case SphincsVariant::Shake128s: return "shake128s";
        case SphincsVariant::Shake192s: return "shake192s";
        case SphincsVariant::Shake256s: return "shake256s";
    }
    return "shake128s";
}

inline int signature_size(SphincsVariant v) {
    switch (v) {
        case SphincsVariant::Shake128s: return 7856;
        case SphincsVariant::Shake192s: return 16224;
        case SphincsVariant::Shake256s: return 29792;
    }
    return 7856;
}

inline int security_level(SphincsVariant v) {
    switch (v) {
        case SphincsVariant::Shake128s: return 128;
        case SphincsVariant::Shake192s: return 192;
        case SphincsVariant::Shake256s: return 256;
    }
    return 128;
}

enum class PqAlgorithm {
    Dilithium3,
    Falcon512,
    Falcon1024,
    Sphincs128s,
    Sphincs192s,
    Sphincs256s
};

enum class AlgorithmFamily {
    Classical,
    Lattice,
    HashBased,
    Hybrid
};

// ============================================================================
// Error Types
// ============================================================================

class CryptoException : public std::runtime_error {
public:
    explicit CryptoException(const std::string& message, const std::string& code = "")
        : std::runtime_error(message), code_(code) {}

    const std::string& code() const { return code_; }

private:
    std::string code_;
};

// ============================================================================
// Configuration Types
// ============================================================================

struct Config {
    std::string api_key;
    std::string endpoint = DEFAULT_ENDPOINT;
    int timeout = 30000;
    int retries = 3;
    bool debug = false;
    Network default_network = Network::Mainnet;

    explicit Config(std::string api_key) : api_key(std::move(api_key)) {}
};

struct DerivationConfig {
    std::vector<uint8_t> salt;
    std::vector<uint8_t> info;
    int output_length = 32;
};

struct PasswordDerivationConfig {
    std::vector<uint8_t> salt;
    int iterations = 100000;
    int output_length = 32;

    explicit PasswordDerivationConfig(std::vector<uint8_t> salt)
        : salt(std::move(salt)) {}
};

struct DerivationPath {
    static constexpr int COIN_TYPE = 0x5359;

    int account;
    int change;
    int index;

    static DerivationPath external_path(int account, int index) {
        return {account, 0, index};
    }

    static DerivationPath internal_path(int account, int index) {
        return {account, 1, index};
    }

    std::string to_string() const {
        return "m/44'/" + std::to_string(COIN_TYPE) + "'/" +
               std::to_string(account) + "'/" +
               std::to_string(change) + "/" +
               std::to_string(index);
    }
};

// ============================================================================
// Key Types
// ============================================================================

struct HybridPublicKey {
    std::string ed25519;
    std::string dilithium;

    std::vector<uint8_t> ed25519_bytes() const;
    std::vector<uint8_t> dilithium_bytes() const;
    size_t size() const;
};

struct SecretKey {
    std::string ed25519_seed;
    std::string master_seed;

    std::vector<uint8_t> ed25519_seed_bytes() const;
    std::vector<uint8_t> master_seed_bytes() const;
};

struct FalconPublicKey {
    FalconVariant variant;
    std::vector<uint8_t> bytes;
};

struct FalconSecretKey {
    FalconVariant variant;
    std::vector<uint8_t> bytes;
};

struct SphincsPublicKey {
    SphincsVariant variant;
    std::vector<uint8_t> bytes;
};

struct SphincsSecretKey {
    SphincsVariant variant;
    std::vector<uint8_t> bytes;
};

// ============================================================================
// Signature Types
// ============================================================================

struct HybridSignature {
    std::string ed25519;
    std::string dilithium;

    std::vector<uint8_t> ed25519_bytes() const;
    std::vector<uint8_t> dilithium_bytes() const;
    size_t size() const;
    std::vector<uint8_t> to_bytes() const;
};

struct FalconSignature {
    FalconVariant variant;
    std::vector<uint8_t> signature;

    size_t size() const { return signature.size(); }
};

struct SphincsSignature {
    SphincsVariant variant;
    std::vector<uint8_t> signature;

    size_t size() const { return signature.size(); }
};

// ============================================================================
// Keypair Types
// ============================================================================

struct HybridKeypair {
    HybridPublicKey public_key;
    SecretKey secret_key;
    std::map<std::string, std::string> addresses;

    std::string get_address(Network network) const;
};

struct FalconKeypair {
    FalconVariant variant;
    FalconPublicKey public_key;
    FalconSecretKey secret_key;
};

struct SphincsKeypair {
    SphincsVariant variant;
    SphincsPublicKey public_key;
    SphincsSecretKey secret_key;
};

// ============================================================================
// Mnemonic Types
// ============================================================================

struct Mnemonic {
    std::string phrase;
    std::vector<std::string> words;
    int word_count = 0;
    std::vector<uint8_t> entropy;

    std::vector<std::string> get_words() const;
    int get_word_count() const;
};

struct MnemonicValidation {
    bool valid;
    std::optional<std::string> error;
};

// ============================================================================
// Address Types
// ============================================================================

struct Address {
    std::string address;
    Network network;
    std::vector<uint8_t> pubkey_hash;
};

// ============================================================================
// Hash Types
// ============================================================================

struct Hash256 {
    std::string hash;

    std::string hex() const { return hash; }
    std::vector<uint8_t> bytes() const;
};

// ============================================================================
// Forward Declarations
// ============================================================================

class SynorCrypto;

// ============================================================================
// Sub-Clients
// ============================================================================

class MnemonicClient {
public:
    explicit MnemonicClient(SynorCrypto* crypto) : crypto_(crypto) {}

    std::future<Mnemonic> generate(int word_count = 24);
    std::future<Mnemonic> from_phrase(const std::string& phrase);
    std::future<MnemonicValidation> validate(const std::string& phrase);
    std::future<std::vector<uint8_t>> to_seed(const std::string& phrase, const std::string& passphrase = "");
    std::future<std::vector<std::string>> suggest_words(const std::string& partial, int limit = 5);

private:
    SynorCrypto* crypto_;
};

class KeypairClient {
public:
    explicit KeypairClient(SynorCrypto* crypto) : crypto_(crypto) {}

    std::future<HybridKeypair> generate();
    std::future<HybridKeypair> from_mnemonic(const std::string& phrase, const std::string& passphrase = "");
    std::future<HybridKeypair> from_seed(const std::vector<uint8_t>& seed);
    std::future<Address> get_address(const HybridPublicKey& public_key, Network network);

private:
    SynorCrypto* crypto_;
};

class SigningClient {
public:
    explicit SigningClient(SynorCrypto* crypto) : crypto_(crypto) {}

    std::future<HybridSignature> sign(const HybridKeypair& keypair, const std::vector<uint8_t>& message);
    std::future<HybridSignature> sign(const HybridKeypair& keypair, const std::string& message);
    std::future<bool> verify(const HybridPublicKey& public_key, const std::vector<uint8_t>& message, const HybridSignature& signature);
    std::future<std::vector<uint8_t>> sign_ed25519(const std::vector<uint8_t>& secret_key, const std::vector<uint8_t>& message);

private:
    SynorCrypto* crypto_;
};

class FalconClient {
public:
    explicit FalconClient(SynorCrypto* crypto) : crypto_(crypto) {}

    std::future<FalconKeypair> generate(FalconVariant variant = FalconVariant::Falcon512);
    std::future<FalconSignature> sign(const FalconKeypair& keypair, const std::vector<uint8_t>& message);
    std::future<bool> verify(const std::vector<uint8_t>& public_key, const std::vector<uint8_t>& message, const FalconSignature& signature);

private:
    SynorCrypto* crypto_;
};

class SphincsClient {
public:
    explicit SphincsClient(SynorCrypto* crypto) : crypto_(crypto) {}

    std::future<SphincsKeypair> generate(SphincsVariant variant = SphincsVariant::Shake128s);
    std::future<SphincsSignature> sign(const SphincsKeypair& keypair, const std::vector<uint8_t>& message);
    std::future<bool> verify(const std::vector<uint8_t>& public_key, const std::vector<uint8_t>& message, const SphincsSignature& signature);

private:
    SynorCrypto* crypto_;
};

class KdfClient {
public:
    explicit KdfClient(SynorCrypto* crypto) : crypto_(crypto) {}

    std::future<std::vector<uint8_t>> derive_key(const std::vector<uint8_t>& seed, const DerivationConfig& config = {});
    std::future<std::vector<uint8_t>> derive_from_password(const std::vector<uint8_t>& password, const PasswordDerivationConfig& config);

private:
    SynorCrypto* crypto_;
};

class HashClient {
public:
    explicit HashClient(SynorCrypto* crypto) : crypto_(crypto) {}

    std::future<Hash256> sha3_256(const std::vector<uint8_t>& data);
    std::future<Hash256> blake3(const std::vector<uint8_t>& data);
    std::future<Hash256> keccak256(const std::vector<uint8_t>& data);

private:
    SynorCrypto* crypto_;
};

// ============================================================================
// Main Client
// ============================================================================

class SynorCrypto {
public:
    explicit SynorCrypto(const Config& config);
    ~SynorCrypto();

    // Non-copyable
    SynorCrypto(const SynorCrypto&) = delete;
    SynorCrypto& operator=(const SynorCrypto&) = delete;

    // Movable
    SynorCrypto(SynorCrypto&&) noexcept;
    SynorCrypto& operator=(SynorCrypto&&) noexcept;

    // Accessors
    Network default_network() const { return config_.default_network; }
    bool is_closed() const { return closed_; }

    // Sub-clients
    MnemonicClient& mnemonic() { return mnemonic_client_; }
    KeypairClient& keypairs() { return keypair_client_; }
    SigningClient& signing() { return signing_client_; }
    FalconClient& falcon() { return falcon_client_; }
    SphincsClient& sphincs() { return sphincs_client_; }
    KdfClient& kdf() { return kdf_client_; }
    HashClient& hash() { return hash_client_; }

    // Operations
    std::future<bool> health_check();
    void close();

    // Internal HTTP methods (used by sub-clients)
    template<typename T>
    std::future<T> get(const std::string& path);

    template<typename T>
    std::future<T> post(const std::string& path, const std::map<std::string, std::string>& body = {});

private:
    void check_closed() const;

    Config config_;
    bool closed_ = false;

    MnemonicClient mnemonic_client_;
    KeypairClient keypair_client_;
    SigningClient signing_client_;
    FalconClient falcon_client_;
    SphincsClient sphincs_client_;
    KdfClient kdf_client_;
    HashClient hash_client_;

    class Impl;
    std::unique_ptr<Impl> impl_;
};

// ============================================================================
// Utility Functions
// ============================================================================

std::string base64_encode(const std::vector<uint8_t>& data);
std::vector<uint8_t> base64_decode(const std::string& encoded);

} // namespace crypto
} // namespace synor

#endif // SYNOR_CRYPTO_HPP
