import Foundation

// MARK: - Confidential Transactions

public struct ConfidentialTxInput: Codable {
    public let commitment: String
    public let blindingFactor: String
    public let value: String
    public let keyImage: String?

    public init(commitment: String, blindingFactor: String, value: String, keyImage: String? = nil) {
        self.commitment = commitment
        self.blindingFactor = blindingFactor
        self.value = value
        self.keyImage = keyImage
    }

    enum CodingKeys: String, CodingKey {
        case commitment
        case blindingFactor = "blinding_factor"
        case value
        case keyImage = "key_image"
    }

    func toDictionary() -> [String: Any] {
        var dict: [String: Any] = [
            "commitment": commitment,
            "blinding_factor": blindingFactor,
            "value": value
        ]
        if let keyImage = keyImage {
            dict["key_image"] = keyImage
        }
        return dict
    }
}

public struct ConfidentialTxOutput: Codable {
    public let commitment: String
    public let blindingFactor: String
    public let value: String
    public let recipientPublicKey: String
    public let rangeProof: String?

    public init(commitment: String, blindingFactor: String, value: String, recipientPublicKey: String, rangeProof: String? = nil) {
        self.commitment = commitment
        self.blindingFactor = blindingFactor
        self.value = value
        self.recipientPublicKey = recipientPublicKey
        self.rangeProof = rangeProof
    }

    enum CodingKeys: String, CodingKey {
        case commitment
        case blindingFactor = "blinding_factor"
        case value
        case recipientPublicKey = "recipient_public_key"
        case rangeProof = "range_proof"
    }

    func toDictionary() -> [String: Any] {
        var dict: [String: Any] = [
            "commitment": commitment,
            "blinding_factor": blindingFactor,
            "value": value,
            "recipient_public_key": recipientPublicKey
        ]
        if let rangeProof = rangeProof {
            dict["range_proof"] = rangeProof
        }
        return dict
    }
}

public struct ConfidentialTransaction: Codable {
    public let id: String
    public let inputs: [ConfidentialTxInput]
    public let outputs: [ConfidentialTxOutput]
    public let fee: String
    public let excess: String
    public let excessSig: String
    public let kernelOffset: String?

    enum CodingKeys: String, CodingKey {
        case id, inputs, outputs, fee, excess
        case excessSig = "excess_sig"
        case kernelOffset = "kernel_offset"
    }

    func toDictionary() -> [String: Any] {
        var dict: [String: Any] = [
            "id": id,
            "inputs": inputs.map { $0.toDictionary() },
            "outputs": outputs.map { $0.toDictionary() },
            "fee": fee,
            "excess": excess,
            "excess_sig": excessSig
        ]
        if let kernelOffset = kernelOffset {
            dict["kernel_offset"] = kernelOffset
        }
        return dict
    }
}

// MARK: - Commitments

public struct Commitment: Codable {
    public let commitment: String
    public let blindingFactor: String

    enum CodingKeys: String, CodingKey {
        case commitment
        case blindingFactor = "blinding_factor"
    }
}

public struct RangeProof: Codable {
    public let proof: String
    public let commitment: String
    public let minValue: Int64
    public let maxValue: Int64

    enum CodingKeys: String, CodingKey {
        case proof, commitment
        case minValue = "min_value"
        case maxValue = "max_value"
    }

    func toDictionary() -> [String: Any] {
        return [
            "proof": proof,
            "commitment": commitment,
            "min_value": minValue,
            "max_value": maxValue
        ]
    }
}

// MARK: - Ring Signatures

public struct RingSignature: Codable {
    public let c0: String
    public let s: [String]
    public let keyImage: String
    public let ring: [String]

    enum CodingKeys: String, CodingKey {
        case c0, s, ring
        case keyImage = "key_image"
    }

    func toDictionary() -> [String: Any] {
        return [
            "c0": c0,
            "s": s,
            "key_image": keyImage,
            "ring": ring
        ]
    }
}

// MARK: - Stealth Addresses

public struct StealthKeyPair: Codable {
    public let spendPublicKey: String
    public let spendPrivateKey: String
    public let viewPublicKey: String
    public let viewPrivateKey: String

    enum CodingKeys: String, CodingKey {
        case spendPublicKey = "spend_public_key"
        case spendPrivateKey = "spend_private_key"
        case viewPublicKey = "view_public_key"
        case viewPrivateKey = "view_private_key"
    }
}

public struct StealthAddress: Codable {
    public let address: String
    public let ephemeralPublicKey: String
    public let txPublicKey: String?

    enum CodingKeys: String, CodingKey {
        case address
        case ephemeralPublicKey = "ephemeral_public_key"
        case txPublicKey = "tx_public_key"
    }
}

public struct StealthOutput: Codable {
    public let txHash: String
    public let outputIndex: Int
    public let stealthAddress: String
    public let amount: String
    public let blockHeight: Int64

    enum CodingKeys: String, CodingKey {
        case txHash = "tx_hash"
        case outputIndex = "output_index"
        case stealthAddress = "stealth_address"
        case amount
        case blockHeight = "block_height"
    }
}
