//! Synor blockchain CLI.
//!
//! Command-line interface for interacting with the Synor blockchain.

#![allow(dead_code)]

use std::path::PathBuf;

use clap::{Parser, Subcommand};

mod client;
mod commands;
mod config;
mod output;
mod wallet;

use crate::client::RpcClient;
use crate::config::CliConfig;

/// Synor blockchain CLI.
#[derive(Parser)]
#[command(name = "synor")]
#[command(version, about = "Synor blockchain CLI", long_about = None)]
struct Cli {
    /// RPC server URL
    #[arg(
        short,
        long,
        env = "SYNOR_RPC_URL",
        default_value = "http://127.0.0.1:16110"
    )]
    rpc: String,

    /// Configuration file path
    #[arg(short, long)]
    config: Option<PathBuf>,

    /// Output format (text, json)
    #[arg(short, long, default_value = "text")]
    output: String,

    /// Enable verbose output
    #[arg(short, long)]
    verbose: bool,

    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    // ==================== Node Commands ====================
    /// Get node information
    Info,

    /// Get node version
    Version,

    /// Get sync status
    SyncStatus,

    /// Get peer information
    Peers,

    // ==================== Block Commands ====================
    /// Get block information
    Block {
        /// Block hash or height
        id: String,
    },

    /// Get latest blocks
    Blocks {
        /// Number of blocks
        #[arg(short, long, default_value = "10")]
        count: usize,
    },

    /// Get current tips
    Tips,

    /// Get block count
    BlockCount,

    // ==================== Transaction Commands ====================
    /// Get transaction information
    Tx {
        /// Transaction hash
        hash: String,
    },

    /// Send transaction
    Send {
        /// Recipient address
        to: String,

        /// Amount in SYNOR
        amount: String,

        /// Fee in SYNOR (optional)
        #[arg(short, long)]
        fee: Option<String>,
    },

    /// Get mempool entries
    Mempool {
        /// Include transaction details
        #[arg(short, long)]
        verbose: bool,
    },

    // ==================== Wallet Commands ====================
    /// Wallet operations
    #[command(subcommand)]
    Wallet(WalletCommands),

    /// Get balance
    Balance {
        /// Address (uses wallet default if not specified)
        address: Option<String>,
    },

    /// Get UTXOs
    Utxos {
        /// Address
        address: String,
    },

    // ==================== Address Commands ====================
    /// Validate an address
    ValidateAddress {
        /// Address to validate
        address: String,
    },

    /// Decode an address
    DecodeAddress {
        /// Address to decode
        address: String,
    },

    // ==================== Mining Commands ====================
    /// Mining operations
    #[command(subcommand)]
    Mining(MiningCommands),

    // ==================== Contract Commands ====================
    /// Contract operations
    #[command(subcommand)]
    Contract(ContractCommands),

    // ==================== Governance Commands ====================
    /// Governance operations (DAO voting, treasury)
    #[command(subcommand)]
    Governance(GovernanceCommands),

    // ==================== Network Commands ====================
    /// Add a peer
    AddPeer {
        /// Peer address (host:port)
        address: String,
    },

    /// Ban a peer
    BanPeer {
        /// Peer address or ID
        peer: String,
    },

    /// Unban a peer
    UnbanPeer {
        /// Peer address or ID
        peer: String,
    },
}

#[derive(Subcommand)]
enum WalletCommands {
    /// Create a new wallet (uses Hybrid keys: Ed25519 + Dilithium)
    Create {
        /// Wallet name
        #[arg(short, long, default_value = "default")]
        name: String,
    },

    /// Import wallet from seed phrase
    Import {
        /// Wallet name
        #[arg(short, long, default_value = "default")]
        name: String,
    },

    /// Export wallet
    Export {
        /// Wallet name
        #[arg(short, long, default_value = "default")]
        name: String,
    },

    /// List wallets
    List,

    /// Get wallet info
    Info {
        /// Wallet name
        #[arg(short, long, default_value = "default")]
        name: String,
    },

    /// Generate new address
    NewAddress {
        /// Wallet name
        #[arg(short, long, default_value = "default")]
        name: String,
    },

    /// List addresses
    Addresses {
        /// Wallet name
        #[arg(short, long, default_value = "default")]
        name: String,
    },
}

#[derive(Subcommand)]
enum MiningCommands {
    /// Get mining info
    Info,

    /// Get block template
    Template {
        /// Coinbase address
        address: String,
    },

    /// Submit a mined block
    Submit {
        /// Block hex
        block: String,
    },

    /// Estimate network hashrate
    Hashrate,
}

#[derive(Subcommand)]
enum ContractCommands {
    /// Deploy a contract
    Deploy {
        /// Path to WASM file
        wasm: PathBuf,

        /// Deployer address (bech32)
        #[arg(short, long)]
        deployer: String,

        /// Constructor arguments (hex)
        #[arg(short, long)]
        args: Option<String>,

        /// Gas limit
        #[arg(short, long, default_value = "1000000")]
        gas: u64,
    },

    /// Call a contract method
    Call {
        /// Contract ID (hex)
        contract_id: String,

        /// Method name
        method: String,

        /// Caller address (bech32)
        #[arg(short, long)]
        caller: String,

        /// Arguments (hex)
        #[arg(short, long)]
        args: Option<String>,

        /// Value to send
        #[arg(short, long, default_value = "0")]
        value: u64,

        /// Gas limit
        #[arg(short, long, default_value = "1000000")]
        gas: u64,
    },

    /// Get contract code
    Code {
        /// Contract ID (hex)
        contract_id: String,
    },

    /// Get contract storage
    Storage {
        /// Contract ID (hex)
        contract_id: String,

        /// Storage key (hex)
        key: String,
    },

    /// Estimate gas for a call
    EstimateGas {
        /// Contract ID (hex)
        contract_id: String,

        /// Method name
        method: String,

        /// Caller address (bech32)
        #[arg(short, long)]
        caller: String,

        /// Arguments (hex)
        #[arg(short, long)]
        args: Option<String>,

        /// Value to send
        #[arg(short, long, default_value = "0")]
        value: u64,
    },

    /// Get contract metadata
    Info {
        /// Contract ID (hex)
        contract_id: String,
    },
}

#[derive(Subcommand)]
enum GovernanceCommands {
    /// Get governance info
    Info,

    /// Get DAO statistics
    Stats,

    /// List proposals
    Proposals {
        /// Filter by state (active, pending, passed, defeated, executed)
        #[arg(short, long)]
        state: Option<String>,
    },

    /// Get proposal details
    Proposal {
        /// Proposal ID (hex)
        id: String,
    },

    /// Create a proposal
    CreateProposal {
        /// Proposer address (bech32)
        #[arg(short, long)]
        proposer: String,

        /// Proposal type (treasury_spend, ecosystem_grant, parameter_change, signaling)
        #[arg(short = 't', long)]
        proposal_type: String,

        /// Proposal title
        #[arg(long)]
        title: String,

        /// Proposal description
        #[arg(short, long)]
        description: String,

        /// Recipient address (for treasury/grant proposals)
        #[arg(long)]
        recipient: Option<String>,

        /// Amount in SYNOR (for treasury/grant proposals)
        #[arg(long)]
        amount: Option<u64>,

        /// Parameter name (for parameter_change proposals)
        #[arg(long)]
        parameter: Option<String>,

        /// Old value (for parameter_change proposals)
        #[arg(long)]
        old_value: Option<String>,

        /// New value (for parameter_change proposals)
        #[arg(long)]
        new_value: Option<String>,
    },

    /// Vote on a proposal
    Vote {
        /// Proposal ID (hex)
        #[arg(short, long)]
        proposal_id: String,

        /// Voter address (bech32)
        #[arg(short, long)]
        voter: String,

        /// Vote choice (yes, no, abstain)
        #[arg(short, long)]
        choice: String,

        /// Optional reason for the vote
        #[arg(short, long)]
        reason: Option<String>,
    },

    /// Execute a passed proposal
    Execute {
        /// Proposal ID (hex)
        #[arg(short, long)]
        proposal_id: String,

        /// Executor address (bech32)
        #[arg(short, long)]
        executor: String,
    },

    /// Get treasury overview
    Treasury,

    /// Get treasury pool details
    TreasuryPool {
        /// Pool ID (hex)
        id: String,
    },
}

#[tokio::main]
async fn main() {
    let cli = Cli::parse();

    // Initialize logging
    if cli.verbose {
        tracing_subscriber::fmt()
            .with_max_level(tracing::Level::DEBUG)
            .init();
    }

    // Load config
    let config = CliConfig::load_or_default(cli.config.as_deref());

    // Create RPC client
    let client = RpcClient::new(&cli.rpc);

    // Set output format
    let output = output::OutputFormat::from_str(&cli.output);

    // Execute command
    let result = match cli.command {
        // Node commands
        Commands::Info => commands::node::info(&client, output).await,
        Commands::Version => commands::node::version(&client, output).await,
        Commands::SyncStatus => commands::node::sync_status(&client, output).await,
        Commands::Peers => commands::node::peers(&client, output).await,

        // Block commands
        Commands::Block { id } => commands::block::get_block(&client, &id, output).await,
        Commands::Blocks { count } => commands::block::get_blocks(&client, count, output).await,
        Commands::Tips => commands::block::get_tips(&client, output).await,
        Commands::BlockCount => commands::block::get_block_count(&client, output).await,

        // Transaction commands
        Commands::Tx { hash } => commands::tx::get_tx(&client, &hash, output).await,
        Commands::Send { to, amount, fee } => {
            commands::tx::send(&client, &config, &to, &amount, fee.as_deref(), output).await
        }
        Commands::Mempool { verbose } => commands::tx::mempool(&client, verbose, output).await,

        // Wallet commands
        Commands::Wallet(cmd) => commands::wallet::handle(&config, cmd, output).await,
        Commands::Balance { address } => {
            commands::wallet::balance(&client, &config, address.as_deref(), output).await
        }
        Commands::Utxos { address } => commands::wallet::utxos(&client, &address, output).await,

        // Address commands
        Commands::ValidateAddress { address } => {
            commands::address::validate(&address, output).await
        }
        Commands::DecodeAddress { address } => commands::address::decode(&address, output).await,

        // Mining commands
        Commands::Mining(cmd) => commands::mining::handle(&client, cmd, output).await,

        // Contract commands
        Commands::Contract(cmd) => commands::contract::handle(&client, &config, cmd, output).await,

        // Governance commands
        Commands::Governance(cmd) => commands::governance::handle(&client, cmd, output).await,

        // Network commands
        Commands::AddPeer { address } => {
            commands::network::add_peer(&client, &address, output).await
        }
        Commands::BanPeer { peer } => commands::network::ban_peer(&client, &peer, output).await,
        Commands::UnbanPeer { peer } => commands::network::unban_peer(&client, &peer, output).await,
    };

    if let Err(e) = result {
        eprintln!("Error: {}", e);
        std::process::exit(1);
    }
}
