/**
 * Synor Compiler SDK for C++
 *
 * Smart contract compilation, optimization, and ABI generation.
 */

#ifndef SYNOR_COMPILER_HPP
#define SYNOR_COMPILER_HPP

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

namespace synor {
namespace compiler {

/* ============================================================================
 * Enumerations
 * ============================================================================ */

/** Optimization level */
enum class OptimizationLevel {
    None,       ///< No optimization
    Basic,      ///< Basic optimizations (stripping only)
    Size,       ///< Optimize for size (-Os equivalent)
    Aggressive  ///< Aggressive optimization (-O3 -Os equivalent)
};

/* ============================================================================
 * Exception
 * ============================================================================ */

class CompilerError : public std::runtime_error {
public:
    CompilerError(const std::string& message,
                  const std::optional<std::string>& code = std::nullopt,
                  const std::optional<int>& status = std::nullopt)
        : std::runtime_error(message), code_(code), status_(status) {}

    const std::optional<std::string>& code() const { return code_; }
    const std::optional<int>& status() const { return status_; }

private:
    std::optional<std::string> code_;
    std::optional<int> status_;
};

/* ============================================================================
 * Data Types
 * ============================================================================ */

/** Strip options */
struct StripOptions {
    bool strip_debug = true;
    bool strip_producers = true;
    bool strip_names = true;
    bool strip_custom = true;
    std::vector<std::string> preserve_sections;
    bool strip_unused = true;
};

/** Compiler configuration */
struct CompilerConfig {
    std::string api_key;
    std::string endpoint = "https://compiler.synor.io/v1";
    std::chrono::milliseconds timeout{60000};
    int retries = 3;
    bool debug = false;
    OptimizationLevel optimization_level = OptimizationLevel::Size;
    std::optional<StripOptions> strip_options;
    size_t max_contract_size = 256 * 1024;
    bool use_wasm_opt = true;
    bool validate = true;
    bool extract_metadata = true;
    bool generate_abi = true;
};

/** Validation error */
struct ValidationError {
    std::string code;
    std::string message;
    std::optional<std::string> location;
};

/** Validation result */
struct ValidationResult {
    bool valid;
    std::vector<ValidationError> errors;
    std::vector<std::string> warnings;
    size_t export_count = 0;
    size_t import_count = 0;
    size_t function_count = 0;
    std::pair<uint32_t, std::optional<uint32_t>> memory_pages = {0, std::nullopt};
};

/** Contract metadata */
struct ContractMetadata {
    std::optional<std::string> name;
    std::optional<std::string> version;
    std::vector<std::string> authors;
    std::optional<std::string> description;
    std::optional<std::string> license;
    std::optional<std::string> repository;
    std::optional<uint64_t> build_timestamp;
    std::optional<std::string> rust_version;
    std::optional<std::string> sdk_version;
    std::map<std::string, std::string> custom;
};

/** Type information */
struct TypeInfo {
    std::string kind;
    std::optional<size_t> size;
    std::unique_ptr<TypeInfo> element;
    std::unique_ptr<TypeInfo> inner;
    std::vector<TypeInfo> elements;
    std::optional<std::string> name;
    std::vector<std::pair<std::string, TypeInfo>> fields;

    std::string type_name() const;
};

/** Parameter ABI */
struct ParamAbi {
    std::string name;
    TypeInfo type;
    bool indexed = false;
};

/** Function ABI */
struct FunctionAbi {
    std::string name;
    std::string selector;
    std::vector<ParamAbi> inputs;
    std::vector<ParamAbi> outputs;
    bool view = false;
    bool payable = false;
    std::optional<std::string> doc;
};

/** Event ABI */
struct EventAbi {
    std::string name;
    std::string topic;
    std::vector<ParamAbi> params;
    std::optional<std::string> doc;
};

/** Error ABI */
struct ErrorAbi {
    std::string name;
    std::string selector;
    std::vector<ParamAbi> params;
    std::optional<std::string> doc;
};

/** Contract ABI */
struct ContractAbi {
    std::string name;
    std::string version;
    std::vector<FunctionAbi> functions;
    std::vector<EventAbi> events;
    std::vector<ErrorAbi> errors;

    const FunctionAbi* find_function(const std::string& name) const;
    const FunctionAbi* find_by_selector(const std::string& selector) const;
    std::string to_json() const;
};

/** Compilation result */
struct CompilationResult {
    std::string contract_id;
    std::vector<uint8_t> code;
    std::string code_hash;
    size_t original_size;
    size_t optimized_size;
    double size_reduction;
    std::optional<ContractMetadata> metadata;
    std::optional<ContractAbi> abi;
    uint64_t estimated_deploy_gas = 0;
    std::optional<ValidationResult> validation;
    std::vector<std::string> warnings;

    std::string size_stats() const;
};

/** Size breakdown */
struct SizeBreakdown {
    size_t code = 0;
    size_t data = 0;
    size_t types = 0;
    size_t functions = 0;
    size_t memory = 0;
    size_t table = 0;
    size_t exports = 0;
    size_t imports = 0;
    size_t custom = 0;
    size_t total = 0;
};

/** Function analysis */
struct FunctionAnalysis {
    std::string name;
    size_t size;
    size_t instruction_count;
    size_t local_count;
    bool exported;
    uint64_t estimated_gas;
};

/** Import analysis */
struct ImportAnalysis {
    std::string module;
    std::string name;
    std::string kind;
    std::optional<std::string> signature;
};

/** Security issue */
struct SecurityIssue {
    std::string severity;
    std::string type;
    std::string description;
    std::optional<std::string> location;
};

/** Security analysis */
struct SecurityAnalysis {
    int score = 0;
    std::vector<SecurityIssue> issues;
    std::vector<std::string> recommendations;
};

/** Gas analysis */
struct GasAnalysis {
    uint64_t deployment_gas = 0;
    std::map<std::string, uint64_t> function_gas;
    uint64_t memory_init_gas = 0;
    uint64_t data_section_gas = 0;
};

/** Contract analysis */
struct ContractAnalysis {
    SizeBreakdown size_breakdown;
    std::vector<FunctionAnalysis> functions;
    std::vector<ImportAnalysis> imports;
    std::optional<SecurityAnalysis> security;
    std::optional<GasAnalysis> gas_analysis;
};

/** Compilation request */
struct CompilationRequest {
    std::optional<OptimizationLevel> optimization_level;
    std::optional<StripOptions> strip_options;
    std::optional<bool> use_wasm_opt;
    std::optional<bool> validate;
    std::optional<bool> extract_metadata;
    std::optional<bool> generate_abi;
};

/* ============================================================================
 * Client Classes
 * ============================================================================ */

class SynorCompiler;

/** Contracts sub-client */
class ContractsClient {
public:
    explicit ContractsClient(SynorCompiler& compiler) : compiler_(compiler) {}

    std::future<CompilationResult> compile(const std::vector<uint8_t>& wasm,
                                           const std::optional<CompilationRequest>& request = std::nullopt);
    std::future<CompilationResult> compile_dev(const std::vector<uint8_t>& wasm);
    std::future<CompilationResult> compile_production(const std::vector<uint8_t>& wasm);
    std::future<CompilationResult> get(const std::string& contract_id);
    std::future<std::vector<CompilationResult>> list(std::optional<int> limit = std::nullopt,
                                                      std::optional<int> offset = std::nullopt);
    std::future<std::vector<uint8_t>> get_code(const std::string& contract_id);

private:
    SynorCompiler& compiler_;
};

/** ABI sub-client */
class AbiClient {
public:
    explicit AbiClient(SynorCompiler& compiler) : compiler_(compiler) {}

    std::future<ContractAbi> extract(const std::vector<uint8_t>& wasm);
    std::future<ContractAbi> get(const std::string& contract_id);
    std::future<std::string> encode_call(const FunctionAbi& func, const std::vector<std::string>& args);
    std::future<std::vector<std::string>> decode_result(const FunctionAbi& func, const std::string& data);

private:
    SynorCompiler& compiler_;
};

/** Analysis sub-client */
class AnalysisClient {
public:
    explicit AnalysisClient(SynorCompiler& compiler) : compiler_(compiler) {}

    std::future<ContractAnalysis> analyze(const std::vector<uint8_t>& wasm);
    std::future<ContractAnalysis> get(const std::string& contract_id);
    std::future<ContractMetadata> extract_metadata(const std::vector<uint8_t>& wasm);
    std::future<uint64_t> estimate_deploy_gas(const std::vector<uint8_t>& wasm);
    std::future<SecurityAnalysis> security_scan(const std::vector<uint8_t>& wasm);

private:
    SynorCompiler& compiler_;
};

/** Validation sub-client */
class ValidationClient {
public:
    explicit ValidationClient(SynorCompiler& compiler) : compiler_(compiler) {}

    std::future<ValidationResult> validate(const std::vector<uint8_t>& wasm);
    std::future<bool> is_valid(const std::vector<uint8_t>& wasm);
    std::future<std::vector<std::string>> get_errors(const std::vector<uint8_t>& wasm);
    std::future<bool> validate_exports(const std::vector<uint8_t>& wasm,
                                        const std::vector<std::string>& required_exports);
    std::future<bool> validate_memory(const std::vector<uint8_t>& wasm, uint32_t max_pages);

private:
    SynorCompiler& compiler_;
};

/**
 * Synor Compiler SDK Client
 *
 * Smart contract compilation, optimization, and ABI generation.
 *
 * Example:
 * @code
 * synor::compiler::CompilerConfig config;
 * config.api_key = "your-api-key";
 * synor::compiler::SynorCompiler compiler(config);
 *
 * auto result = compiler.compile(wasm_bytes).get();
 * std::cout << "Optimized size: " << result.optimized_size << " bytes" << std::endl;
 * @endcode
 */
class SynorCompiler {
public:
    explicit SynorCompiler(const CompilerConfig& config);
    ~SynorCompiler();

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

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

    /** Get the default optimization level */
    OptimizationLevel default_optimization_level() const { return config_.optimization_level; }

    /** Health check */
    std::future<bool> health_check();

    /** Get service info */
    std::future<std::map<std::string, std::string>> get_info();

    /** Close the client */
    void close();

    /** Check if client is closed */
    bool is_closed() const { return closed_; }

    /** Compile WASM bytecode */
    std::future<CompilationResult> compile(const std::vector<uint8_t>& wasm,
                                           const std::optional<CompilationRequest>& request = std::nullopt);

    /** Sub-clients */
    ContractsClient& contracts() { return contracts_; }
    AbiClient& abi() { return abi_; }
    AnalysisClient& analysis() { return analysis_; }
    ValidationClient& validation() { return validation_; }

    // Internal HTTP methods (public for sub-clients)
    std::future<std::map<std::string, std::string>> get(const std::string& path);
    std::future<std::map<std::string, std::string>> post(const std::string& path,
                                                          const std::map<std::string, std::string>& body);

private:
    CompilerConfig config_;
    bool closed_ = false;
    ContractsClient contracts_;
    AbiClient abi_;
    AnalysisClient analysis_;
    ValidationClient validation_;
};

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

/** Convert optimization level to string */
std::string optimization_level_to_string(OptimizationLevel level);

/** Parse optimization level from string */
OptimizationLevel optimization_level_from_string(const std::string& str);

/* ============================================================================
 * Constants
 * ============================================================================ */

constexpr size_t MAX_CONTRACT_SIZE = 256 * 1024;
constexpr uint32_t MAX_MEMORY_PAGES = 16;

} // namespace compiler
} // namespace synor

#endif // SYNOR_COMPILER_HPP
