/**
 * @file governance.hpp
 * @brief Synor Governance SDK for C++
 *
 * Modern C++17 SDK for proposals, voting, DAOs, and vesting operations.
 */

#pragma once

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

namespace synor {
namespace governance {

/// Proposal status
enum class ProposalStatus {
    Pending,
    Active,
    Passed,
    Rejected,
    Executed,
    Cancelled
};

/// Vote choice
enum class VoteChoice {
    For,
    Against,
    Abstain
};

/// DAO type
enum class DaoType {
    Token,
    Multisig,
    Hybrid
};

/// Vesting status
enum class VestingStatus {
    Active,
    Completed,
    Revoked
};

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

/// Proposal action
struct ProposalAction {
    std::string target;
    std::string method;
    std::string data;
    std::optional<std::string> value;
};

/// Proposal draft
struct ProposalDraft {
    std::string title;
    std::string description;
    std::optional<std::string> discussion_url;
    std::optional<int64_t> voting_start_time;
    std::optional<int64_t> voting_end_time;
    std::optional<std::string> dao_id;
    std::vector<ProposalAction> actions;
};

/// Vote tally
struct VoteTally {
    std::string for_votes;
    std::string against_votes;
    std::string abstain_votes;
    std::string quorum;
    std::string quorum_required;
    int32_t total_voters;
};

/// Proposal
struct Proposal {
    std::string id;
    std::string title;
    std::string description;
    std::optional<std::string> discussion_url;
    std::string proposer;
    ProposalStatus status;
    int64_t created_at;
    int64_t voting_start_time;
    int64_t voting_end_time;
    std::optional<int64_t> execution_time;
    VoteTally vote_tally;
    std::vector<ProposalAction> actions;
    std::optional<std::string> dao_id;
};

/// Proposal filter
struct ProposalFilter {
    std::optional<ProposalStatus> status;
    std::optional<std::string> proposer;
    std::optional<std::string> dao_id;
    std::optional<int32_t> limit;
    std::optional<int32_t> offset;
};

/// Vote
struct Vote {
    VoteChoice choice;
    std::optional<std::string> reason;
};

/// Vote receipt
struct VoteReceipt {
    std::string id;
    std::string proposal_id;
    std::string voter;
    VoteChoice choice;
    std::string weight;
    std::optional<std::string> reason;
    int64_t voted_at;
    std::string tx_hash;
};

/// Voting power
struct VotingPower {
    std::string address;
    std::string delegated_power;
    std::string own_power;
    std::string total_power;
    std::vector<std::string> delegators;
};

/// Delegation receipt
struct DelegationReceipt {
    std::string id;
    std::string from;
    std::string to;
    std::string amount;
    int64_t delegated_at;
    std::string tx_hash;
};

/// DAO configuration
struct DaoConfig {
    std::string name;
    std::string description;
    DaoType type;
    int32_t voting_period_days;
    int32_t timelock_days;
    std::optional<std::string> token_address;
    std::optional<double> quorum_percent;
    std::optional<std::string> proposal_threshold;
    std::vector<std::string> multisig_members;
    std::optional<int32_t> multisig_threshold;
};

/// DAO
struct Dao {
    std::string id;
    std::string name;
    std::string description;
    DaoType type;
    std::optional<std::string> token_address;
    int32_t voting_period_days;
    int32_t timelock_days;
    double quorum_percent;
    std::string proposal_threshold;
    int32_t total_proposals;
    int32_t active_proposals;
    std::string treasury_value;
    int32_t member_count;
    int64_t created_at;
};

/// Treasury token
struct TreasuryToken {
    std::string address;
    std::string balance;
    std::string name;
    std::string symbol;
};

/// DAO treasury
struct DaoTreasury {
    std::string dao_id;
    std::string total_value;
    std::vector<TreasuryToken> tokens;
    int64_t last_updated;
};

/// Vesting schedule
struct VestingSchedule {
    std::string beneficiary;
    std::string total_amount;
    int64_t start_time;
    int64_t cliff_duration;
    int64_t vesting_duration;
    bool revocable;
};

/// Vesting contract
struct VestingContract {
    std::string id;
    std::string beneficiary;
    std::string grantor;
    std::string total_amount;
    std::string released_amount;
    std::string releasable_amount;
    int64_t start_time;
    int64_t cliff_time;
    int64_t end_time;
    VestingStatus status;
    bool revocable;
    int64_t created_at;
};

/// Claim receipt
struct ClaimReceipt {
    std::string id;
    std::string contract_id;
    std::string amount;
    std::string tx_hash;
    int64_t claimed_at;
};

// Forward declaration
class SynorGovernanceImpl;

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

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

    // Proposal operations
    std::future<Proposal> create_proposal(const ProposalDraft& draft);
    std::future<Proposal> get_proposal(const std::string& proposal_id);
    std::future<std::vector<Proposal>> list_proposals(const ProposalFilter& filter = {});
    std::future<Proposal> cancel_proposal(const std::string& proposal_id);
    std::future<Proposal> execute_proposal(const std::string& proposal_id);
    std::future<Proposal> wait_for_proposal(
        const std::string& proposal_id,
        std::chrono::milliseconds poll_interval = std::chrono::minutes(1),
        std::chrono::milliseconds max_wait = std::chrono::hours(168));

    // Voting operations
    std::future<VoteReceipt> vote(const std::string& proposal_id, const Vote& vote,
                                   std::optional<std::string> weight = std::nullopt);
    std::future<std::vector<VoteReceipt>> get_votes(const std::string& proposal_id);
    std::future<VoteReceipt> get_my_vote(const std::string& proposal_id);
    std::future<DelegationReceipt> delegate(const std::string& delegatee,
                                            std::optional<std::string> amount = std::nullopt);
    std::future<DelegationReceipt> undelegate(const std::string& delegatee);
    std::future<VotingPower> get_voting_power(const std::string& address);
    std::future<std::vector<DelegationReceipt>> get_delegations(const std::string& address);

    // DAO operations
    std::future<Dao> create_dao(const DaoConfig& config);
    std::future<Dao> get_dao(const std::string& dao_id);
    std::future<std::vector<Dao>> list_daos(std::optional<int32_t> limit = std::nullopt,
                                             std::optional<int32_t> offset = std::nullopt);
    std::future<DaoTreasury> get_dao_treasury(const std::string& dao_id);
    std::future<std::vector<std::string>> get_dao_members(const std::string& dao_id);

    // Vesting operations
    std::future<VestingContract> create_vesting_schedule(const VestingSchedule& schedule);
    std::future<VestingContract> get_vesting_contract(const std::string& contract_id);
    std::future<std::vector<VestingContract>> list_vesting_contracts(
        std::optional<std::string> beneficiary = std::nullopt);
    std::future<ClaimReceipt> claim_vested(const std::string& contract_id);
    std::future<VestingContract> revoke_vesting(const std::string& contract_id);
    std::future<std::string> get_releasable_amount(const std::string& contract_id);

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

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

}  // namespace governance
}  // namespace synor
