//! Contract SDK types

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Default contract endpoint
pub const DEFAULT_CONTRACT_ENDPOINT: &str = "https://contract.synor.cc/api/v1";

/// Contract client configuration
#[derive(Clone, Debug)]
pub struct ContractConfig {
    pub api_key: String,
    pub endpoint: String,
    pub timeout_secs: u64,
    pub retries: u32,
    pub debug: bool,
    pub default_gas_limit: Option<String>,
    pub default_gas_price: Option<String>,
}

impl Default for ContractConfig {
    fn default() -> Self {
        Self {
            api_key: String::new(),
            endpoint: DEFAULT_CONTRACT_ENDPOINT.to_string(),
            timeout_secs: 30,
            retries: 3,
            debug: false,
            default_gas_limit: None,
            default_gas_price: None,
        }
    }
}

/// ABI entry type
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum AbiEntryType {
    Function,
    Constructor,
    Event,
    Error,
    Fallback,
    Receive,
}

/// State mutability
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum StateMutability {
    Pure,
    View,
    Nonpayable,
    Payable,
}

/// Transaction status
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum TransactionStatus {
    Success,
    Reverted,
}

/// Verification status
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum VerificationStatus {
    Verified,
    Pending,
    Failed,
}

/// ABI parameter
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AbiParameter {
    pub name: String,
    #[serde(rename = "type")]
    pub param_type: String,
    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
    pub indexed: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub components: Option<Vec<AbiParameter>>,
    #[serde(rename = "internalType", skip_serializing_if = "Option::is_none")]
    pub internal_type: Option<String>,
}

/// ABI entry
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AbiEntry {
    #[serde(rename = "type")]
    pub entry_type: AbiEntryType,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub inputs: Option<Vec<AbiParameter>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub outputs: Option<Vec<AbiParameter>>,
    #[serde(rename = "stateMutability", skip_serializing_if = "Option::is_none")]
    pub state_mutability: Option<StateMutability>,
    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
    pub anonymous: bool,
}

/// Contract ABI
pub type Abi = Vec<AbiEntry>;

/// Deployment result
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DeploymentResult {
    pub address: String,
    #[serde(rename = "transactionHash")]
    pub transaction_hash: String,
    #[serde(rename = "blockNumber")]
    pub block_number: u64,
    #[serde(rename = "gasUsed")]
    pub gas_used: String,
    #[serde(rename = "effectiveGasPrice")]
    pub effective_gas_price: String,
}

/// Event log
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct EventLog {
    #[serde(rename = "logIndex")]
    pub log_index: u32,
    pub address: String,
    pub topics: Vec<String>,
    pub data: String,
    #[serde(rename = "blockNumber")]
    pub block_number: u64,
    #[serde(rename = "transactionHash")]
    pub transaction_hash: String,
}

/// Decoded event
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DecodedEvent {
    pub name: String,
    pub signature: String,
    pub args: HashMap<String, serde_json::Value>,
    pub log: EventLog,
}

/// Transaction result
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TransactionResult {
    #[serde(rename = "transactionHash")]
    pub transaction_hash: String,
    #[serde(rename = "blockNumber")]
    pub block_number: u64,
    #[serde(rename = "blockHash")]
    pub block_hash: String,
    #[serde(rename = "gasUsed")]
    pub gas_used: String,
    #[serde(rename = "effectiveGasPrice")]
    pub effective_gas_price: String,
    pub status: TransactionStatus,
    pub logs: Vec<EventLog>,
    #[serde(rename = "returnValue", skip_serializing_if = "Option::is_none")]
    pub return_value: Option<serde_json::Value>,
    #[serde(rename = "revertReason", skip_serializing_if = "Option::is_none")]
    pub revert_reason: Option<String>,
}

/// Contract interface
#[derive(Clone, Debug)]
pub struct ContractInterface {
    pub abi: Abi,
    pub functions: HashMap<String, AbiEntry>,
    pub events: HashMap<String, AbiEntry>,
    pub errors: HashMap<String, AbiEntry>,
}

/// Gas estimation
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct GasEstimation {
    #[serde(rename = "gasLimit")]
    pub gas_limit: String,
    #[serde(rename = "gasPrice")]
    pub gas_price: String,
    #[serde(rename = "estimatedCost")]
    pub estimated_cost: String,
}

/// Bytecode metadata
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BytecodeMetadata {
    pub compiler: String,
    pub language: String,
    pub sources: Vec<String>,
}

/// Bytecode info
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BytecodeInfo {
    pub bytecode: String,
    #[serde(rename = "deployedBytecode", skip_serializing_if = "Option::is_none")]
    pub deployed_bytecode: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub abi: Option<Abi>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<BytecodeMetadata>,
}

/// Verification result
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VerificationResult {
    pub status: VerificationStatus,
    pub message: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub abi: Option<Abi>,
}

/// Multicall request
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MulticallRequest {
    pub address: String,
    #[serde(rename = "callData")]
    pub call_data: String,
    #[serde(rename = "allowFailure", default)]
    pub allow_failure: bool,
}

/// Multicall result
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MulticallResult {
    pub success: bool,
    #[serde(rename = "returnData")]
    pub return_data: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub decoded: Option<serde_json::Value>,
}

/// Deploy options
#[derive(Clone, Debug, Default)]
pub struct DeployOptions {
    pub bytecode: String,
    pub abi: Option<Abi>,
    pub args: Option<Vec<serde_json::Value>>,
    pub gas_limit: Option<String>,
    pub gas_price: Option<String>,
    pub value: Option<String>,
    pub salt: Option<String>,
}

/// Call options
#[derive(Clone, Debug)]
pub struct CallOptions {
    pub address: String,
    pub method: String,
    pub abi: Abi,
    pub args: Option<Vec<serde_json::Value>>,
    pub block_number: Option<BlockNumber>,
}

/// Send options
#[derive(Clone, Debug)]
pub struct SendOptions {
    pub address: String,
    pub method: String,
    pub abi: Abi,
    pub args: Option<Vec<serde_json::Value>>,
    pub gas_limit: Option<String>,
    pub gas_price: Option<String>,
    pub value: Option<String>,
}

/// Block number specifier
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum BlockNumber {
    Number(u64),
    Tag(String),
}

impl Default for BlockNumber {
    fn default() -> Self {
        BlockNumber::Tag("latest".to_string())
    }
}

/// Event filter
#[derive(Clone, Debug, Default)]
pub struct EventFilter {
    pub address: String,
    pub event_name: Option<String>,
    pub abi: Option<Abi>,
    pub from_block: Option<BlockNumber>,
    pub to_block: Option<BlockNumber>,
    pub filter: Option<HashMap<String, serde_json::Value>>,
}

/// Estimate gas options
#[derive(Clone, Debug, Default)]
pub struct EstimateGasOptions {
    pub address: Option<String>,
    pub method: Option<String>,
    pub args: Option<Vec<serde_json::Value>>,
    pub abi: Option<Abi>,
    pub bytecode: Option<String>,
    pub value: Option<String>,
    pub from: Option<String>,
}

/// Verify contract options
#[derive(Clone, Debug)]
pub struct VerifyContractOptions {
    pub address: String,
    pub source_code: String,
    pub compiler_version: String,
    pub constructor_arguments: Option<String>,
    pub optimization: bool,
    pub optimization_runs: u32,
    pub contract_name: Option<String>,
}
