//! Synor RPC SDK Types.

use serde::{Deserialize, Serialize};

/// Network type.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum Network {
    #[default]
    Mainnet,
    Testnet,
}

/// Transaction priority levels.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum Priority {
    Low,
    #[default]
    Medium,
    High,
    Urgent,
}

/// Transaction status.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum TransactionStatus {
    Pending,
    Confirmed,
    Failed,
    Replaced,
}

/// Subscription type.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SubscriptionType {
    Blocks,
    Transactions,
    Address,
    Mempool,
}

/// RPC client configuration.
#[derive(Debug, Clone)]
pub struct RpcConfig {
    pub api_key: String,
    pub endpoint: String,
    pub ws_endpoint: String,
    pub network: Network,
    pub timeout_secs: u64,
    pub debug: bool,
}

impl RpcConfig {
    /// Create a new configuration with the given API key.
    pub fn new(api_key: impl Into<String>) -> Self {
        Self {
            api_key: api_key.into(),
            endpoint: "https://rpc.synor.cc/api/v1".to_string(),
            ws_endpoint: "wss://rpc.synor.cc/ws".to_string(),
            network: Network::default(),
            timeout_secs: 30,
            debug: false,
        }
    }

    /// Set the endpoint.
    pub fn endpoint(mut self, endpoint: impl Into<String>) -> Self {
        self.endpoint = endpoint.into();
        self
    }

    /// Set the WebSocket endpoint.
    pub fn ws_endpoint(mut self, ws_endpoint: impl Into<String>) -> Self {
        self.ws_endpoint = ws_endpoint.into();
        self
    }

    /// Set the network.
    pub fn network(mut self, network: Network) -> Self {
        self.network = network;
        self
    }

    /// Set the timeout in seconds.
    pub fn timeout(mut self, secs: u64) -> Self {
        self.timeout_secs = secs;
        self
    }

    /// Enable debug mode.
    pub fn debug(mut self, debug: bool) -> Self {
        self.debug = debug;
        self
    }
}

/// Block header.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BlockHeader {
    pub hash: String,
    pub height: i64,
    pub version: i32,
    pub previous_hash: String,
    pub merkle_root: String,
    pub timestamp: i64,
    pub difficulty: String,
    pub nonce: u64,
}

/// Full block with transactions.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Block {
    pub hash: String,
    pub height: i64,
    pub version: i32,
    pub previous_hash: String,
    pub merkle_root: String,
    pub timestamp: i64,
    pub difficulty: String,
    pub nonce: u64,
    pub transactions: Vec<String>,
    pub size: i32,
    pub weight: i32,
    pub tx_count: i32,
}

/// Transaction input.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TxInput {
    pub txid: String,
    pub vout: i32,
    pub script_sig: String,
    pub sequence: u32,
}

/// Script pubkey.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ScriptPubKey {
    pub asm: String,
    pub hex: String,
    #[serde(rename = "type")]
    pub script_type: String,
    #[serde(default)]
    pub addresses: Vec<String>,
}

/// Transaction output.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TxOutput {
    pub value: String,
    pub n: i32,
    pub script_pub_key: ScriptPubKey,
}

/// Transaction.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Transaction {
    pub txid: String,
    pub confirmations: i32,
    pub status: TransactionStatus,
    pub size: i32,
    pub fee: String,
    #[serde(default)]
    pub inputs: Vec<TxInput>,
    #[serde(default)]
    pub outputs: Vec<TxOutput>,
    pub block_hash: Option<String>,
    pub block_height: Option<i64>,
    pub timestamp: Option<i64>,
    pub raw: Option<String>,
}

/// Fee estimation result.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FeeEstimate {
    pub priority: Priority,
    pub fee_rate: String,
    pub estimated_blocks: i32,
}

/// Chain information.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ChainInfo {
    pub chain: String,
    pub network: String,
    pub height: i64,
    pub best_block_hash: String,
    pub difficulty: String,
    pub median_time: i64,
    pub chain_work: String,
    pub syncing: bool,
    pub sync_progress: f64,
}

/// Mempool information.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MempoolInfo {
    pub size: i32,
    pub bytes: i64,
    pub usage: i64,
    pub max_mempool: i64,
    pub min_fee: String,
}

/// Unspent transaction output.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Utxo {
    pub txid: String,
    pub vout: i32,
    pub amount: String,
    pub address: String,
    pub confirmations: i32,
    pub script_pub_key: Option<String>,
}

/// Balance information.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Balance {
    pub confirmed: String,
    pub unconfirmed: String,
    pub total: String,
}

/// WebSocket subscription.
#[derive(Debug, Clone)]
pub struct Subscription {
    pub id: String,
    pub subscription_type: SubscriptionType,
    pub created_at: i64,
}
