# frozen_string_literal: true

module SynorWallet
  # Network environment
  module Network
    MAINNET = "mainnet"
    TESTNET = "testnet"
    DEVNET = "devnet"
  end

  # Wallet types
  module WalletType
    STANDARD = "standard"
    MULTISIG = "multisig"
    HARDWARE = "hardware"
  end

  # Address types
  module AddressType
    P2PKH = "p2pkh"
    P2SH = "p2sh"
    P2WPKH = "p2wpkh"
    P2WSH = "p2wsh"
  end

  # Transaction priority
  module Priority
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
  end

  # Configuration
  class Config
    attr_reader :api_key, :base_url, :network, :timeout, :retries, :debug

    def initialize(
      api_key:,
      base_url: "https://wallet.synor.io/v1",
      network: Network::MAINNET,
      timeout: 30,
      retries: 3,
      debug: false
    )
      @api_key = api_key
      @base_url = base_url
      @network = network
      @timeout = timeout
      @retries = retries
      @debug = debug
    end
  end

  # Address information
  class Address
    attr_reader :address, :type, :index, :is_change, :public_key

    def initialize(address:, type:, index:, is_change: false, public_key: nil)
      @address = address
      @type = type
      @index = index
      @is_change = is_change
      @public_key = public_key
    end

    def self.from_hash(h)
      new(
        address: h["address"],
        type: h["type"],
        index: h["index"],
        is_change: h["is_change"] || false,
        public_key: h["public_key"]
      )
    end
  end

  # Stealth address
  class StealthAddress
    attr_reader :scan_public_key, :spend_public_key, :address

    def initialize(scan_public_key:, spend_public_key:, address:)
      @scan_public_key = scan_public_key
      @spend_public_key = spend_public_key
      @address = address
    end

    def self.from_hash(h)
      new(
        scan_public_key: h["scan_public_key"],
        spend_public_key: h["spend_public_key"],
        address: h["address"]
      )
    end
  end

  # Wallet information
  class Wallet
    attr_reader :id, :name, :type, :network, :addresses, :created_at

    def initialize(id:, name:, type:, network:, addresses:, created_at:)
      @id = id
      @name = name
      @type = type
      @network = network
      @addresses = addresses
      @created_at = created_at
    end

    def self.from_hash(h)
      new(
        id: h["id"],
        name: h["name"],
        type: h["type"],
        network: h["network"],
        addresses: (h["addresses"] || []).map { |a| Address.from_hash(a) },
        created_at: h["created_at"]
      )
    end
  end

  # Create wallet result
  class CreateWalletResult
    attr_reader :wallet, :mnemonic

    def initialize(wallet:, mnemonic:)
      @wallet = wallet
      @mnemonic = mnemonic
    end

    def self.from_hash(h)
      new(
        wallet: Wallet.from_hash(h["wallet"]),
        mnemonic: h["mnemonic"]
      )
    end
  end

  # Balance information
  class Balance
    attr_reader :confirmed, :unconfirmed, :total

    def initialize(confirmed:, unconfirmed:, total:)
      @confirmed = confirmed
      @unconfirmed = unconfirmed
      @total = total
    end

    def self.from_hash(h)
      new(
        confirmed: h["confirmed"],
        unconfirmed: h["unconfirmed"],
        total: h["total"]
      )
    end
  end

  # UTXO
  class UTXO
    attr_reader :txid, :vout, :value, :confirmations, :script_pubkey

    def initialize(txid:, vout:, value:, confirmations:, script_pubkey:)
      @txid = txid
      @vout = vout
      @value = value
      @confirmations = confirmations
      @script_pubkey = script_pubkey
    end

    def self.from_hash(h)
      new(
        txid: h["txid"],
        vout: h["vout"],
        value: h["value"],
        confirmations: h["confirmations"],
        script_pubkey: h["script_pubkey"]
      )
    end
  end

  # Transaction input
  class TransactionInput
    attr_reader :txid, :vout, :sequence

    def initialize(txid:, vout:, sequence: 0xFFFFFFFF)
      @txid = txid
      @vout = vout
      @sequence = sequence
    end

    def to_h
      { txid: @txid, vout: @vout, sequence: @sequence }
    end
  end

  # Transaction output
  class TransactionOutput
    attr_reader :address, :value

    def initialize(address:, value:)
      @address = address
      @value = value
    end

    def to_h
      { address: @address, value: @value }
    end
  end

  # Transaction
  class Transaction
    attr_reader :inputs, :outputs, :lock_time

    def initialize(inputs:, outputs:, lock_time: 0)
      @inputs = inputs
      @outputs = outputs
      @lock_time = lock_time
    end

    def to_h
      {
        inputs: @inputs.map(&:to_h),
        outputs: @outputs.map(&:to_h),
        lock_time: @lock_time
      }
    end
  end

  # Signed transaction
  class SignedTransaction
    attr_reader :txid, :raw, :size, :weight, :fee

    def initialize(txid:, raw:, size:, weight:, fee:)
      @txid = txid
      @raw = raw
      @size = size
      @weight = weight
      @fee = fee
    end

    def self.from_hash(h)
      new(
        txid: h["txid"],
        raw: h["raw"],
        size: h["size"],
        weight: h["weight"],
        fee: h["fee"]
      )
    end
  end

  # Signature
  class Signature
    attr_reader :signature, :recovery_id, :address

    def initialize(signature:, recovery_id:, address:)
      @signature = signature
      @recovery_id = recovery_id
      @address = address
    end

    def self.from_hash(h)
      new(
        signature: h["signature"],
        recovery_id: h["recovery_id"],
        address: h["address"]
      )
    end
  end
end
