package io.synor.contract

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement

// ==================== ABI Types ====================

@Serializable
data class AbiParameter(
    val name: String? = null,
    val type: String,
    val indexed: Boolean? = null,
    val components: List<AbiParameter>? = null
)

@Serializable
data class AbiEntry(
    val type: String,
    val name: String? = null,
    val inputs: List<AbiParameter>? = null,
    val outputs: List<AbiParameter>? = null,
    val stateMutability: String? = null,
    val anonymous: Boolean? = null
)

// ==================== Deployment ====================

data class DeployContractOptions(
    val bytecode: String,
    val abi: List<AbiEntry>? = null,
    val constructorArgs: List<Any?>? = null,
    val value: String? = null,
    val gasLimit: Long? = null,
    val gasPrice: String? = null,
    val nonce: Long? = null
)

@Serializable
data class DeploymentResult(
    @SerialName("contract_address") val contractAddress: String,
    @SerialName("transaction_hash") val transactionHash: String,
    val deployer: String? = null,
    @SerialName("gas_used") val gasUsed: Long? = null,
    @SerialName("block_number") val blockNumber: Long? = null,
    @SerialName("block_hash") val blockHash: String? = null
)

// ==================== Contract Interaction ====================

data class CallContractOptions(
    val contract: String,
    val method: String,
    val args: List<Any?> = emptyList(),
    val abi: List<AbiEntry>
)

data class SendContractOptions(
    val contract: String,
    val method: String,
    val args: List<Any?> = emptyList(),
    val abi: List<AbiEntry>,
    val value: String? = null,
    val gasLimit: Long? = null,
    val gasPrice: String? = null,
    val nonce: Long? = null
)

@Serializable
data class TransactionResult(
    @SerialName("transaction_hash") val transactionHash: String,
    @SerialName("block_number") val blockNumber: Long? = null,
    @SerialName("block_hash") val blockHash: String? = null,
    @SerialName("gas_used") val gasUsed: Long? = null,
    @SerialName("effective_gas_price") val effectiveGasPrice: String? = null,
    val status: String? = null,
    val logs: List<EventLog>? = null
)

// ==================== Events ====================

@Serializable
data class EventLog(
    val address: String,
    val topics: List<String>,
    val data: String,
    @SerialName("block_number") val blockNumber: Long? = null,
    @SerialName("transaction_hash") val transactionHash: String? = null,
    @SerialName("log_index") val logIndex: Int? = null,
    @SerialName("block_hash") val blockHash: String? = null,
    val removed: Boolean? = null
)

@Serializable
data class DecodedEvent(
    val name: String,
    val signature: String? = null,
    val args: Map<String, JsonElement>? = null,
    val log: EventLog? = null
)

data class EventFilter(
    val contract: String,
    val event: String? = null,
    val fromBlock: Long? = null,
    val toBlock: Long? = null,
    val topics: List<String?>? = null,
    val abi: List<AbiEntry>? = null
)

// ==================== ABI Utilities ====================

data class EncodeCallOptions(
    val method: String,
    val args: List<Any?> = emptyList(),
    val abi: List<AbiEntry>
)

data class DecodeResultOptions(
    val data: String,
    val method: String,
    val abi: List<AbiEntry>
)

// ==================== Gas Estimation ====================

data class EstimateGasOptions(
    val contract: String,
    val method: String,
    val args: List<Any?> = emptyList(),
    val abi: List<AbiEntry>,
    val value: String? = null
)

@Serializable
data class GasEstimation(
    @SerialName("gas_limit") val gasLimit: Long,
    @SerialName("gas_price") val gasPrice: String? = null,
    @SerialName("max_fee_per_gas") val maxFeePerGas: String? = null,
    @SerialName("max_priority_fee_per_gas") val maxPriorityFeePerGas: String? = null,
    @SerialName("estimated_cost") val estimatedCost: String? = null
)

// ==================== Contract Information ====================

@Serializable
data class BytecodeInfo(
    val bytecode: String,
    @SerialName("deployed_bytecode") val deployedBytecode: String? = null,
    val size: Int? = null,
    @SerialName("is_contract") val isContract: Boolean? = null
)

data class VerifyContractOptions(
    val address: String,
    val sourceCode: String,
    val compilerVersion: String,
    val constructorArgs: String? = null,
    val optimization: Boolean? = null,
    val optimizationRuns: Int? = null,
    val license: String? = null
)

@Serializable
data class VerificationResult(
    val verified: Boolean,
    val address: String? = null,
    @SerialName("compiler_version") val compilerVersion: String? = null,
    val optimization: Boolean? = null,
    @SerialName("optimization_runs") val optimizationRuns: Int? = null,
    val license: String? = null,
    val abi: List<AbiEntry>? = null,
    @SerialName("source_code") val sourceCode: String? = null
)

// ==================== Multicall ====================

@Serializable
data class MulticallRequest(
    val contract: String,
    val method: String,
    val args: List<JsonElement> = emptyList(),
    val abi: List<AbiEntry>
)

@Serializable
data class MulticallResult(
    val success: Boolean,
    val result: JsonElement? = null,
    val error: String? = null
)

// ==================== Storage ====================

data class ReadStorageOptions(
    val contract: String,
    val slot: String,
    val blockNumber: Long? = null
)
