//! RPC service.

use std::net::SocketAddr;
use std::sync::Arc;

use jsonrpsee::server::{ServerBuilder, ServerHandle};
use jsonrpsee::RpcModule;
use tokio::sync::RwLock;
use tracing::{info, warn};

use synor_network::SyncState;
use synor_types::{block::BlockBody, BlockHeader};

use crate::config::NodeConfig;
use crate::services::{
    ConsensusService, ContractService, MempoolService, NetworkService, StorageService,
};

/// RPC service context for handlers.
#[derive(Clone)]
pub struct RpcContext {
    pub storage: Arc<StorageService>,
    pub network: Arc<NetworkService>,
    pub consensus: Arc<ConsensusService>,
    pub mempool: Arc<MempoolService>,
    pub contract: Arc<ContractService>,
}

/// RPC service manages the JSON-RPC server.
pub struct RpcService {
    /// Storage reference.
    storage: Arc<StorageService>,

    /// Network reference.
    network: Arc<NetworkService>,

    /// Consensus reference.
    consensus: Arc<ConsensusService>,

    /// Mempool reference.
    mempool: Arc<MempoolService>,

    /// Contract service reference.
    contract: Arc<ContractService>,

    /// HTTP bind address.
    http_addr: String,

    /// WebSocket bind address.
    ws_addr: String,

    /// Enable HTTP.
    http_enabled: bool,

    /// Enable WebSocket.
    ws_enabled: bool,

    /// Is running.
    running: RwLock<bool>,

    /// HTTP server handle.
    http_handle: RwLock<Option<ServerHandle>>,

    /// WebSocket server handle.
    ws_handle: RwLock<Option<ServerHandle>>,
}

impl RpcService {
    /// Creates a new RPC service.
    pub fn new(
        storage: Arc<StorageService>,
        network: Arc<NetworkService>,
        consensus: Arc<ConsensusService>,
        mempool: Arc<MempoolService>,
        contract: Arc<ContractService>,
        config: &NodeConfig,
    ) -> anyhow::Result<Self> {
        Ok(RpcService {
            storage,
            network,
            consensus,
            mempool,
            contract,
            http_addr: config.rpc.http_addr.clone(),
            ws_addr: config.rpc.ws_addr.clone(),
            http_enabled: config.rpc.http_enabled,
            ws_enabled: config.rpc.ws_enabled,
            running: RwLock::new(false),
            http_handle: RwLock::new(None),
            ws_handle: RwLock::new(None),
        })
    }

    /// Starts the RPC service.
    pub async fn start(&self) -> anyhow::Result<()> {
        info!("Starting RPC service");

        // Create RPC context for handlers
        let context = RpcContext {
            storage: self.storage.clone(),
            network: self.network.clone(),
            consensus: self.consensus.clone(),
            mempool: self.mempool.clone(),
            contract: self.contract.clone(),
        };

        // Build RPC module with all methods
        let module = self.build_module(context)?;

        // Start HTTP server
        if self.http_enabled {
            let http_addr: SocketAddr = self
                .http_addr
                .parse()
                .map_err(|e| anyhow::anyhow!("Invalid HTTP address: {}", e))?;

            info!(addr = %http_addr, "Starting HTTP RPC server");

            let server = ServerBuilder::default()
                .build(http_addr)
                .await
                .map_err(|e| anyhow::anyhow!("Failed to start HTTP server: {}", e))?;

            let local_addr = server
                .local_addr()
                .map_err(|e| anyhow::anyhow!("Failed to get local address: {}", e))?;
            info!(addr = %local_addr, "HTTP RPC server started");

            let handle = server.start(module.clone());
            *self.http_handle.write().await = Some(handle);
        }

        // Start WebSocket server
        if self.ws_enabled {
            let ws_addr: SocketAddr = self
                .ws_addr
                .parse()
                .map_err(|e| anyhow::anyhow!("Invalid WebSocket address: {}", e))?;

            info!(addr = %ws_addr, "Starting WebSocket RPC server");

            let server = ServerBuilder::default()
                .build(ws_addr)
                .await
                .map_err(|e| anyhow::anyhow!("Failed to start WebSocket server: {}", e))?;

            let local_addr = server
                .local_addr()
                .map_err(|e| anyhow::anyhow!("Failed to get local address: {}", e))?;
            info!(addr = %local_addr, "WebSocket RPC server started");

            let handle = server.start(module);
            *self.ws_handle.write().await = Some(handle);
        }

        *self.running.write().await = true;
        Ok(())
    }

    /// Stops the RPC service.
    pub async fn stop(&self) -> anyhow::Result<()> {
        info!("Stopping RPC service");

        // Stop HTTP server
        if let Some(handle) = self.http_handle.write().await.take() {
            if let Err(e) = handle.stop() {
                warn!("Error stopping HTTP server: {:?}", e);
            }
            info!("HTTP RPC server stopped");
        }

        // Stop WebSocket server
        if let Some(handle) = self.ws_handle.write().await.take() {
            if let Err(e) = handle.stop() {
                warn!("Error stopping WebSocket server: {:?}", e);
            }
            info!("WebSocket RPC server stopped");
        }

        *self.running.write().await = false;
        Ok(())
    }

    /// Builds the RPC module with all methods.
    fn build_module(&self, ctx: RpcContext) -> anyhow::Result<RpcModule<RpcContext>> {
        let mut module = RpcModule::new(ctx);

        // Register base methods
        self.register_base_methods(&mut module)?;

        // Register block methods
        self.register_block_methods(&mut module)?;

        // Register transaction methods
        self.register_tx_methods(&mut module)?;

        // Register network methods
        self.register_network_methods(&mut module)?;

        // Register mining methods
        self.register_mining_methods(&mut module)?;

        // Register contract methods
        self.register_contract_methods(&mut module)?;

        Ok(module)
    }

    /// Registers base methods.
    fn register_base_methods(&self, module: &mut RpcModule<RpcContext>) -> anyhow::Result<()> {
        // synor_getServerVersion
        module.register_method("synor_getServerVersion", |_, _| {
            serde_json::json!({
                "version": env!("CARGO_PKG_VERSION"),
                "name": "synord"
            })
        })?;

        // synor_echo - for testing
        module.register_method("synor_echo", |params, _| {
            let message: String = params.one().unwrap_or_default();
            message
        })?;

        Ok(())
    }

    /// Registers block-related methods.
    fn register_block_methods(&self, module: &mut RpcModule<RpcContext>) -> anyhow::Result<()> {
        // synor_getBlockCount
        module.register_async_method("synor_getBlockCount", |_, ctx| async move {
            let count = ctx.consensus.current_height().await;
            serde_json::json!({"blockCount": count})
        })?;

        // synor_getBlueScore
        module.register_async_method("synor_getBlueScore", |_, ctx| async move {
            let score = ctx.consensus.current_blue_score().await;
            serde_json::json!({"blueScore": score})
        })?;

        // synor_getTips
        module.register_async_method("synor_getTips", |_, ctx| async move {
            let tips = ctx.consensus.tips().await;
            let tip_strings: Vec<String> = tips.iter().map(hex::encode).collect();
            serde_json::json!({"tips": tip_strings})
        })?;

        // synor_getBlocksByBlueScore
        module.register_async_method("synor_getBlocksByBlueScore", |params, ctx| async move {
            let parsed: (u64, Option<bool>) = match params.parse() {
                Ok(p) => p,
                Err(_) => return serde_json::json!([]),
            };
            let (blue_score, include_txs) = parsed;
            let include_txs = include_txs.unwrap_or(false);

            let block_hashes = ctx.consensus.get_blocks_by_blue_score(blue_score).await;

            let mut blocks = Vec::new();
            for hash in block_hashes {
                if let Ok(Some(block_data)) = ctx.storage.get_block(&hash).await {
                    // Deserialize header and body from raw bytes
                    let header: BlockHeader = match borsh::from_slice(&block_data.header) {
                        Ok(h) => h,
                        Err(_) => continue,
                    };
                    let body: BlockBody = match borsh::from_slice(&block_data.body) {
                        Ok(b) => b,
                        Err(_) => continue,
                    };

                    let block_json = serde_json::json!({
                        "hash": hex::encode(hash),
                        "header": {
                            "version": header.version,
                            "parents": header.parents.iter().map(|p| hex::encode(p.as_bytes())).collect::<Vec<_>>(),
                            "hashMerkleRoot": hex::encode(header.merkle_root.as_bytes()),
                            "utxoCommitment": hex::encode(header.utxo_commitment.as_bytes()),
                            "timestamp": header.timestamp.as_millis(),
                            "bits": header.bits,
                            "nonce": header.nonce,
                            "blueScore": blue_score
                        },
                        "transactions": if include_txs {
                            body.transactions.iter().map(|tx| {
                                serde_json::json!({
                                    "hash": hex::encode(tx.txid().as_bytes()),
                                    "inputs": tx.inputs.len(),
                                    "outputs": tx.outputs.len()
                                })
                            }).collect::<Vec<_>>()
                        } else {
                            vec![]
                        }
                    });
                    blocks.push(block_json);
                }
            }

            serde_json::json!(blocks)
        })?;

        Ok(())
    }

    /// Registers transaction methods.
    fn register_tx_methods(&self, module: &mut RpcModule<RpcContext>) -> anyhow::Result<()> {
        // synor_getMempoolSize
        module.register_async_method("synor_getMempoolSize", |_, ctx| async move {
            let size = ctx.mempool.count().await;
            serde_json::json!({"size": size})
        })?;

        Ok(())
    }

    /// Registers network methods.
    fn register_network_methods(&self, module: &mut RpcModule<RpcContext>) -> anyhow::Result<()> {
        // synor_getInfo
        module.register_async_method("synor_getInfo", |_, ctx| async move {
            let peer_count = ctx.network.peer_count().await;
            let block_count = ctx.consensus.current_height().await;
            let blue_score = ctx.consensus.current_blue_score().await;
            let mempool_size = ctx.mempool.count().await;

            // Check actual sync status from network service
            let synced = ctx
                .network
                .sync_status()
                .await
                .map(|status| matches!(status.state, SyncState::Synced | SyncState::Idle))
                .unwrap_or(false);

            serde_json::json!({
                "version": env!("CARGO_PKG_VERSION"),
                "protocolVersion": 1,
                "peerCount": peer_count,
                "blockCount": block_count,
                "blueScore": blue_score,
                "mempoolSize": mempool_size,
                "synced": synced
            })
        })?;

        // synor_getPeerCount
        module.register_async_method("synor_getPeerCount", |_, ctx| async move {
            let count = ctx.network.peer_count().await;
            serde_json::json!({"peerCount": count})
        })?;

        // synor_getPeerInfo
        module.register_async_method("synor_getPeerInfo", |_, ctx| async move {
            let peers = ctx.network.peers().await;
            let peer_info: Vec<serde_json::Value> = peers
                .iter()
                .map(|p| {
                    serde_json::json!({
                        "id": p.id,
                        "address": p.address.map(|a| a.to_string()).unwrap_or_default(),
                        "isInbound": p.inbound,
                        "version": p.version,
                        "userAgent": p.user_agent,
                        "latencyMs": p.latency_ms
                    })
                })
                .collect();
            serde_json::json!({"peers": peer_info})
        })?;

        Ok(())
    }

    /// Registers mining methods.
    fn register_mining_methods(&self, module: &mut RpcModule<RpcContext>) -> anyhow::Result<()> {
        // synor_getMiningInfo
        module.register_async_method("synor_getMiningInfo", |_, ctx| async move {
            let block_count = ctx.consensus.current_height().await;
            let difficulty_bits = ctx.consensus.current_difficulty().await;

            // Convert compact difficulty bits to difficulty value
            // difficulty = max_target / current_target
            // For simplified calculation, use the exponent and mantissa from compact bits
            let exponent = (difficulty_bits >> 24) as u64;
            let mantissa = (difficulty_bits & 0x00FFFFFF) as u64;
            let difficulty = if exponent <= 3 {
                (mantissa >> (8 * (3 - exponent))) as f64
            } else {
                (mantissa as f64) * (256.0_f64).powi((exponent - 3) as i32)
            };

            // Estimate network hashrate based on difficulty
            // hashrate ≈ difficulty × 2^32 / block_time_seconds
            // With 100ms (0.1s) block time target:
            let block_time_seconds = 0.1_f64;
            let network_hashrate = if difficulty > 0.0 {
                (difficulty * 4_294_967_296.0 / block_time_seconds) as u64
            } else {
                0
            };

            serde_json::json!({
                "blocks": block_count,
                "difficulty": difficulty,
                "networkhashps": network_hashrate
            })
        })?;

        Ok(())
    }

    /// Registers smart contract methods.
    fn register_contract_methods(&self, module: &mut RpcModule<RpcContext>) -> anyhow::Result<()> {
        // synor_deployContract - Deploy a new contract
        module.register_async_method("synor_deployContract", |params, ctx| async move {
            #[derive(serde::Deserialize)]
            struct DeployParams {
                bytecode: String,
                #[serde(default)]
                init_args: String,
                deployer: synor_types::Address,
                #[serde(default)]
                gas_limit: Option<u64>,
            }

            let params: DeployParams = match params.parse() {
                Ok(p) => p,
                Err(e) => return serde_json::json!({"error": format!("Invalid params: {}", e)}),
            };

            let bytecode = match hex::decode(&params.bytecode) {
                Ok(b) => b,
                Err(e) => {
                    return serde_json::json!({"error": format!("Invalid bytecode hex: {}", e)})
                }
            };

            let init_args = if params.init_args.is_empty() {
                Vec::new()
            } else {
                match hex::decode(&params.init_args) {
                    Ok(a) => a,
                    Err(e) => {
                        return serde_json::json!({"error": format!("Invalid init_args hex: {}", e)})
                    }
                }
            };

            let block_height = ctx.consensus.current_height().await;
            let timestamp = current_timestamp();

            match ctx
                .contract
                .deploy(
                    bytecode,
                    init_args,
                    &params.deployer,
                    params.gas_limit,
                    block_height,
                    timestamp,
                )
                .await
            {
                Ok(result) => serde_json::json!({
                    "contractId": hex::encode(result.contract_id),
                    "address": hex::encode(&result.address),
                    "gasUsed": result.gas_used
                }),
                Err(e) => serde_json::json!({
                    "error": e.to_string()
                }),
            }
        })?;

        // synor_callContract - Call a contract method
        module.register_async_method("synor_callContract", |params, ctx| async move {
            #[derive(serde::Deserialize)]
            struct CallParams {
                contract_id: String,
                method: String,
                #[serde(default)]
                args: String,
                caller: synor_types::Address,
                #[serde(default)]
                value: u64,
                #[serde(default)]
                gas_limit: Option<u64>,
            }

            let params: CallParams = match params.parse() {
                Ok(p) => p,
                Err(e) => return serde_json::json!({"error": format!("Invalid params: {}", e)}),
            };

            let contract_id = match hex_to_hash(&params.contract_id) {
                Ok(id) => id,
                Err(e) => {
                    return serde_json::json!({"error": format!("Invalid contract_id: {}", e)})
                }
            };

            let args = if params.args.is_empty() {
                Vec::new()
            } else {
                match hex::decode(&params.args) {
                    Ok(a) => a,
                    Err(e) => {
                        return serde_json::json!({"error": format!("Invalid args hex: {}", e)})
                    }
                }
            };

            let block_height = ctx.consensus.current_height().await;
            let timestamp = current_timestamp();

            match ctx
                .contract
                .call(
                    &contract_id,
                    &params.method,
                    args,
                    &params.caller,
                    params.value,
                    params.gas_limit,
                    block_height,
                    timestamp,
                )
                .await
            {
                Ok(result) => {
                    let logs: Vec<serde_json::Value> = result
                        .logs
                        .iter()
                        .map(|log| {
                            serde_json::json!({
                                "contractId": hex::encode(log.contract_id),
                                "topics": log.topics.iter().map(hex::encode).collect::<Vec<_>>(),
                                "data": hex::encode(&log.data)
                            })
                        })
                        .collect();

                    serde_json::json!({
                        "success": result.success,
                        "data": hex::encode(&result.data),
                        "gasUsed": result.gas_used,
                        "logs": logs
                    })
                }
                Err(e) => serde_json::json!({
                    "error": e.to_string()
                }),
            }
        })?;

        // synor_estimateGas - Estimate gas for a contract call
        module.register_async_method("synor_estimateGas", |params, ctx| async move {
            #[derive(serde::Deserialize)]
            struct EstimateParams {
                contract_id: String,
                method: String,
                #[serde(default)]
                args: String,
                caller: synor_types::Address,
                #[serde(default)]
                value: u64,
            }

            let params: EstimateParams = match params.parse() {
                Ok(p) => p,
                Err(e) => return serde_json::json!({"error": format!("Invalid params: {}", e)}),
            };

            let contract_id = match hex_to_hash(&params.contract_id) {
                Ok(id) => id,
                Err(e) => {
                    return serde_json::json!({"error": format!("Invalid contract_id: {}", e)})
                }
            };

            let args = if params.args.is_empty() {
                Vec::new()
            } else {
                match hex::decode(&params.args) {
                    Ok(a) => a,
                    Err(e) => {
                        return serde_json::json!({"error": format!("Invalid args hex: {}", e)})
                    }
                }
            };

            let block_height = ctx.consensus.current_height().await;
            let timestamp = current_timestamp();

            match ctx
                .contract
                .estimate_gas(
                    &contract_id,
                    &params.method,
                    args,
                    &params.caller,
                    params.value,
                    block_height,
                    timestamp,
                )
                .await
            {
                Ok(gas) => serde_json::json!({
                    "estimatedGas": gas
                }),
                Err(e) => serde_json::json!({
                    "error": e.to_string()
                }),
            }
        })?;

        // synor_getCode - Get contract bytecode
        module.register_async_method("synor_getCode", |params, ctx| async move {
            #[derive(serde::Deserialize)]
            struct GetCodeParams {
                contract_id: String,
            }

            let params: GetCodeParams = match params.parse() {
                Ok(p) => p,
                Err(e) => return serde_json::json!({"error": format!("Invalid params: {}", e)}),
            };

            let contract_id = match hex_to_hash(&params.contract_id) {
                Ok(id) => id,
                Err(e) => {
                    return serde_json::json!({"error": format!("Invalid contract_id: {}", e)})
                }
            };

            match ctx.contract.get_code(&contract_id).await {
                Ok(Some(code)) => serde_json::json!({
                    "code": hex::encode(&code)
                }),
                Ok(None) => serde_json::json!({
                    "code": null
                }),
                Err(e) => serde_json::json!({
                    "error": e.to_string()
                }),
            }
        })?;

        // synor_getStorageAt - Get contract storage value
        module.register_async_method("synor_getStorageAt", |params, ctx| async move {
            #[derive(serde::Deserialize)]
            struct GetStorageParams {
                contract_id: String,
                key: String,
            }

            let params: GetStorageParams = match params.parse() {
                Ok(p) => p,
                Err(e) => return serde_json::json!({"error": format!("Invalid params: {}", e)}),
            };

            let contract_id = match hex_to_hash(&params.contract_id) {
                Ok(id) => id,
                Err(e) => {
                    return serde_json::json!({"error": format!("Invalid contract_id: {}", e)})
                }
            };

            let key = match hex_to_hash(&params.key) {
                Ok(k) => k,
                Err(e) => return serde_json::json!({"error": format!("Invalid key: {}", e)}),
            };

            match ctx.contract.get_storage_at(&contract_id, &key).await {
                Ok(Some(value)) => serde_json::json!({
                    "value": hex::encode(&value)
                }),
                Ok(None) => serde_json::json!({
                    "value": null
                }),
                Err(e) => serde_json::json!({
                    "error": e.to_string()
                }),
            }
        })?;

        // synor_getContract - Get contract metadata
        module.register_async_method("synor_getContract", |params, ctx| async move {
            #[derive(serde::Deserialize)]
            struct GetContractParams {
                contract_id: String,
            }

            let params: GetContractParams = match params.parse() {
                Ok(p) => p,
                Err(e) => return serde_json::json!({"error": format!("Invalid params: {}", e)}),
            };

            let contract_id = match hex_to_hash(&params.contract_id) {
                Ok(id) => id,
                Err(e) => {
                    return serde_json::json!({"error": format!("Invalid contract_id: {}", e)})
                }
            };

            match ctx.contract.get_contract(&contract_id).await {
                Ok(Some(contract)) => serde_json::json!({
                    "codeHash": hex::encode(contract.code_hash),
                    "deployer": hex::encode(&contract.deployer),
                    "deployedAt": contract.deployed_at,
                    "deployedHeight": contract.deployed_height
                }),
                Ok(None) => serde_json::json!({
                    "contract": null
                }),
                Err(e) => serde_json::json!({
                    "error": e.to_string()
                }),
            }
        })?;

        Ok(())
    }
}

/// RPC handlers implementation.
impl RpcService {
    // ==================== Block Methods ====================

    /// Gets a block by hash.
    pub async fn get_block(
        &self,
        hash: &str,
        _include_txs: bool,
    ) -> anyhow::Result<Option<RpcBlock>> {
        let hash_bytes = hex_to_hash(hash)?;
        let block_data = self.storage.get_block(&hash_bytes).await?;

        if let Some(_data) = block_data {
            Ok(Some(RpcBlock {
                hash: hash.to_string(),
                header: RpcBlockHeader {
                    version: 1,
                    parents: vec![],
                    hash_merkle_root: String::new(),
                    utxo_commitment: String::new(),
                    timestamp: 0,
                    bits: 0,
                    nonce: 0,
                    blue_score: 0,
                    blue_work: String::new(),
                    pruning_point: None,
                },
                transactions: vec![],
                verbose_data: None,
            }))
        } else {
            Ok(None)
        }
    }

    /// Gets the current block count.
    pub async fn get_block_count(&self) -> u64 {
        self.consensus.current_height().await
    }

    /// Gets current tips.
    pub async fn get_tips(&self) -> Vec<String> {
        self.consensus
            .tips()
            .await
            .iter()
            .map(hex::encode)
            .collect()
    }

    // ==================== Transaction Methods ====================

    /// Submits a transaction.
    pub async fn submit_transaction(&self, tx_hex: &str) -> anyhow::Result<String> {
        let tx_bytes = hex::decode(tx_hex)?;

        // Validate
        let validation = self.consensus.validate_tx(&tx_bytes).await;
        match validation {
            crate::services::consensus::TxValidation::Valid => {
                // Add to mempool
                let hash = compute_tx_hash(&tx_bytes);
                let tx = crate::services::mempool::MempoolTx {
                    hash,
                    data: tx_bytes,
                    mass: 100, // TODO: Calculate
                    fee: 0,    // TODO: Calculate
                    fee_rate: 0.0,
                    timestamp: current_timestamp(),
                    dependencies: vec![],
                    high_priority: false,
                };
                self.mempool.add_transaction(tx).await?;

                // Announce to network
                self.network.announce_tx(hash).await;

                Ok(hex::encode(hash))
            }
            crate::services::consensus::TxValidation::Invalid { reason } => {
                anyhow::bail!("Invalid transaction: {}", reason)
            }
            crate::services::consensus::TxValidation::Duplicate => {
                anyhow::bail!("Transaction already exists")
            }
            crate::services::consensus::TxValidation::Conflict => {
                anyhow::bail!("Transaction conflicts with existing")
            }
        }
    }

    /// Gets transaction from mempool or chain.
    pub async fn get_transaction(&self, hash: &str) -> anyhow::Result<Option<RpcTransaction>> {
        let hash_bytes = hex_to_hash(hash)?;

        // Check mempool first
        if let Some(mempool_tx) = self.mempool.get_transaction(&hash_bytes).await {
            return Ok(Some(RpcTransaction {
                hash: hash.to_string(),
                inputs: vec![],
                outputs: vec![],
                mass: mempool_tx.mass,
                fee: mempool_tx.fee,
                verbose_data: None,
            }));
        }

        // TODO: Check chain
        Ok(None)
    }

    // ==================== Network Methods ====================

    /// Gets node info.
    pub async fn get_info(&self) -> RpcNodeInfo {
        RpcNodeInfo {
            version: env!("CARGO_PKG_VERSION").to_string(),
            protocol_version: 1,
            network: "mainnet".to_string(), // TODO: From config
            peer_count: self.network.peer_count().await,
            synced: true, // TODO: Check sync state
            block_count: self.consensus.current_height().await,
            blue_score: self.consensus.current_blue_score().await,
            mempool_size: self.mempool.count().await,
        }
    }

    /// Gets connected peers.
    pub async fn get_peer_info(&self) -> Vec<RpcPeerInfo> {
        self.network
            .peers()
            .await
            .into_iter()
            .map(|p| RpcPeerInfo {
                id: p.id,
                address: p.address.map(|a| a.to_string()).unwrap_or_default(),
                is_inbound: p.inbound,
                version: p.version,
                user_agent: p.user_agent,
                latency_ms: p.latency_ms,
            })
            .collect()
    }

    // ==================== Mining Methods ====================

    /// Gets block template for mining.
    pub async fn get_block_template(&self, _pay_address: &str) -> anyhow::Result<RpcBlockTemplate> {
        // TODO: Get template from miner service
        Ok(RpcBlockTemplate {
            header: RpcBlockHeader {
                version: 1,
                parents: self.get_tips().await,
                hash_merkle_root: String::new(),
                utxo_commitment: String::new(),
                timestamp: current_timestamp(),
                bits: 0x1e0fffff,
                nonce: 0,
                blue_score: self.consensus.current_blue_score().await,
                blue_work: String::new(),
                pruning_point: None,
            },
            transactions: vec![],
            target: "00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string(),
            is_synced: true,
        })
    }
}

// ==================== RPC Types ====================

#[derive(Clone, Debug)]
pub struct RpcBlock {
    pub hash: String,
    pub header: RpcBlockHeader,
    pub transactions: Vec<RpcTransaction>,
    pub verbose_data: Option<RpcBlockVerboseData>,
}

#[derive(Clone, Debug)]
pub struct RpcBlockHeader {
    pub version: u32,
    pub parents: Vec<String>,
    pub hash_merkle_root: String,
    pub utxo_commitment: String,
    pub timestamp: u64,
    pub bits: u32,
    pub nonce: u64,
    pub blue_score: u64,
    pub blue_work: String,
    pub pruning_point: Option<String>,
}

#[derive(Clone, Debug)]
pub struct RpcBlockVerboseData {
    pub hash: String,
    pub blue_score: u64,
    pub is_chain_block: bool,
    pub selected_parent: Option<String>,
    pub children: Vec<String>,
}

#[derive(Clone, Debug)]
pub struct RpcTransaction {
    pub hash: String,
    pub inputs: Vec<RpcTxInput>,
    pub outputs: Vec<RpcTxOutput>,
    pub mass: u64,
    pub fee: u64,
    pub verbose_data: Option<RpcTxVerboseData>,
}

#[derive(Clone, Debug)]
pub struct RpcTxInput {
    pub previous_outpoint: RpcOutpoint,
    pub signature_script: String,
    pub sig_op_count: u32,
}

#[derive(Clone, Debug)]
pub struct RpcOutpoint {
    pub transaction_id: String,
    pub index: u32,
}

#[derive(Clone, Debug)]
pub struct RpcTxOutput {
    pub value: u64,
    pub script_public_key: String,
}

#[derive(Clone, Debug)]
pub struct RpcTxVerboseData {
    pub block_hash: Option<String>,
    pub confirmations: u64,
    pub accepting_block_hash: Option<String>,
}

#[derive(Clone, Debug)]
pub struct RpcNodeInfo {
    pub version: String,
    pub protocol_version: u32,
    pub network: String,
    pub peer_count: usize,
    pub synced: bool,
    pub block_count: u64,
    pub blue_score: u64,
    pub mempool_size: usize,
}

#[derive(Clone, Debug)]
pub struct RpcPeerInfo {
    pub id: String,
    pub address: String,
    pub is_inbound: bool,
    pub version: u32,
    pub user_agent: String,
    pub latency_ms: u32,
}

#[derive(Clone, Debug)]
pub struct RpcBlockTemplate {
    pub header: RpcBlockHeader,
    pub transactions: Vec<RpcTransaction>,
    pub target: String,
    pub is_synced: bool,
}

// ==================== Helpers ====================

fn hex_to_hash(hex: &str) -> anyhow::Result<[u8; 32]> {
    let bytes = hex::decode(hex)?;
    if bytes.len() != 32 {
        anyhow::bail!("Invalid hash length");
    }
    let mut arr = [0u8; 32];
    arr.copy_from_slice(&bytes);
    Ok(arr)
}

fn compute_tx_hash(tx: &[u8]) -> [u8; 32] {
    blake3::hash(tx).into()
}

fn current_timestamp() -> u64 {
    std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .unwrap()
        .as_millis() as u64
}
