/**
 * @file mining.hpp
 * @brief Synor Mining SDK for C++
 *
 * Modern C++17 SDK for pool connections, block templates, hashrate stats, and GPU management.
 */

#pragma once

#include <string>
#include <vector>
#include <optional>
#include <future>
#include <memory>
#include <cstdint>
#include "wallet.hpp"  // For SynorException

namespace synor {
namespace mining {

/// Device type
enum class DeviceType {
    Cpu,
    GpuNvidia,
    GpuAmd,
    Asic
};

/// Device status
enum class DeviceStatus {
    Idle,
    Mining,
    Error,
    Offline
};

/// Connection status
enum class ConnectionStatus {
    Disconnected,
    Connecting,
    Connected,
    Reconnecting
};

/// Time period for stats
enum class TimePeriod {
    Hour,
    Day,
    Week,
    Month,
    All
};

/// Submit result status
enum class SubmitStatus {
    Accepted,
    Rejected,
    Stale
};

/// Mining configuration
struct Config {
    std::string api_key;
    std::string endpoint = "https://mining.synor.io/v1";
    uint32_t timeout_ms = 60000;
    uint32_t retries = 3;
    bool debug = false;
};

/// Pool configuration
struct PoolConfig {
    std::string url;
    std::string user;
    std::optional<std::string> password;
    std::optional<std::string> algorithm;
    std::optional<double> difficulty;
};

/// Stratum connection
struct StratumConnection {
    std::string id;
    std::string pool;
    ConnectionStatus status;
    std::string algorithm;
    double difficulty;
    int64_t connected_at;
    int32_t accepted_shares;
    int32_t rejected_shares;
    int32_t stale_shares;
    std::optional<int64_t> last_share_at;
};

/// Pool stats
struct PoolStats {
    std::string url;
    int32_t workers;
    double hashrate;
    double difficulty;
    int64_t last_block;
    int32_t blocks_found_24h;
    double luck;
};

/// Template transaction
struct TemplateTransaction {
    std::string txid;
    std::string data;
    std::string fee;
    int32_t weight;
};

/// Block template
struct BlockTemplate {
    std::string id;
    std::string previous_block_hash;
    std::string merkle_root;
    int64_t timestamp;
    std::string bits;
    int64_t height;
    std::string coinbase_value;
    std::vector<TemplateTransaction> transactions;
    std::string target;
    std::string algorithm;
    std::string extra_nonce;
};

/// Mined work
struct MinedWork {
    std::string template_id;
    std::string nonce;
    std::string extra_nonce;
    int64_t timestamp;
    std::string hash;
};

/// Share info
struct ShareInfo {
    std::string hash;
    double difficulty;
    int64_t timestamp;
    bool accepted;
};

/// Submit result
struct SubmitResult {
    SubmitStatus status;
    ShareInfo share;
    bool block_found;
    std::optional<std::string> reason;
    std::optional<std::string> block_hash;
    std::optional<std::string> reward;
};

/// Hashrate
struct Hashrate {
    double current;
    double average_1h;
    double average_24h;
    double peak;
    std::string unit;
};

/// Share stats
struct ShareStats {
    int32_t accepted;
    int32_t rejected;
    int32_t stale;
    int32_t total;
    double accept_rate;
};

/// Device temperature
struct DeviceTemperature {
    double current;
    double max;
    bool throttling;
};

/// Earnings snapshot
struct EarningsSnapshot {
    std::string today;
    std::string yesterday;
    std::string this_week;
    std::string this_month;
    std::string total;
    std::string currency;
};

/// Mining stats
struct MiningStats {
    Hashrate hashrate;
    ShareStats shares;
    int64_t uptime;
    double efficiency;
    EarningsSnapshot earnings;
    std::optional<double> power_consumption;
    std::optional<DeviceTemperature> temperature;
};

/// Earnings breakdown
struct EarningsBreakdown {
    int64_t date;
    std::string amount;
    int32_t blocks;
    int32_t shares;
    double hashrate;
};

/// Earnings report
struct Earnings {
    TimePeriod period;
    int64_t start_date;
    int64_t end_date;
    std::string amount;
    int32_t blocks;
    int32_t shares;
    double average_hashrate;
    std::string currency;
    std::vector<EarningsBreakdown> breakdown;
};

/// Mining device
struct MiningDevice {
    std::string id;
    std::string name;
    DeviceType type;
    DeviceStatus status;
    double hashrate;
    double temperature;
    double fan_speed;
    double power_draw;
    int64_t memory_used;
    int64_t memory_total;
    std::optional<std::string> driver;
    std::optional<std::string> firmware;
};

/// Device configuration
struct DeviceConfig {
    bool enabled;
    std::optional<int32_t> intensity;
    std::optional<int32_t> power_limit;
    std::optional<int32_t> core_clock_offset;
    std::optional<int32_t> memory_clock_offset;
    std::optional<int32_t> fan_speed;
};

/// Worker info
struct WorkerInfo {
    std::string id;
    std::string name;
    ConnectionStatus status;
    Hashrate hashrate;
    ShareStats shares;
    std::vector<MiningDevice> devices;
    int64_t last_seen;
    int64_t uptime;
};

/// Mining algorithm
struct MiningAlgorithm {
    std::string name;
    std::string display_name;
    std::string hash_unit;
    std::string profitability;
    double difficulty;
    std::string block_reward;
    int32_t block_time;
};

// Forward declaration
class SynorMiningImpl;

/// Synor Mining client
class SynorMining {
public:
    explicit SynorMining(const Config& config);
    ~SynorMining();

    SynorMining(const SynorMining&) = delete;
    SynorMining& operator=(const SynorMining&) = delete;
    SynorMining(SynorMining&&) noexcept;
    SynorMining& operator=(SynorMining&&) noexcept;

    // Pool operations
    std::future<StratumConnection> connect(const PoolConfig& pool);
    std::future<void> disconnect();
    std::future<StratumConnection> get_connection();
    std::future<PoolStats> get_pool_stats();
    bool is_connected() const;

    // Mining operations
    std::future<BlockTemplate> get_block_template();
    std::future<SubmitResult> submit_work(const MinedWork& work);
    std::future<void> start_mining(std::optional<std::string> algorithm = std::nullopt);
    std::future<void> stop_mining();
    std::future<bool> is_mining();

    // Stats operations
    std::future<Hashrate> get_hashrate();
    std::future<MiningStats> get_stats();
    std::future<Earnings> get_earnings(std::optional<TimePeriod> period = std::nullopt);
    std::future<ShareStats> get_share_stats();

    // Device operations
    std::future<std::vector<MiningDevice>> list_devices();
    std::future<MiningDevice> get_device(const std::string& device_id);
    std::future<MiningDevice> set_device_config(const std::string& device_id,
                                                 const DeviceConfig& config);
    std::future<void> enable_device(const std::string& device_id);
    std::future<void> disable_device(const std::string& device_id);

    // Worker operations
    std::future<std::vector<WorkerInfo>> list_workers();
    std::future<WorkerInfo> get_worker(const std::string& worker_id);
    std::future<void> remove_worker(const std::string& worker_id);

    // Algorithm operations
    std::future<std::vector<MiningAlgorithm>> list_algorithms();
    std::future<MiningAlgorithm> get_algorithm(const std::string& name);
    std::future<void> switch_algorithm(const std::string& algorithm);
    std::future<MiningAlgorithm> get_most_profitable();

    // Lifecycle
    void close();
    bool is_closed() const;
    std::future<bool> health_check();

private:
    std::unique_ptr<SynorMiningImpl> impl_;
};

}  // namespace mining
}  // namespace synor
