defmodule Indexer.Fetcher.ContractCodeTest do
  use EthereumJSONRPC.Case, async: false
  use Explorer.DataCase

  import EthereumJSONRPC, only: [integer_to_quantity: 1]

  import Mox

  alias Explorer.Chain.{Address, Transaction}
  alias Indexer.Fetcher.ContractCode

  @moduletag :capture_log

  # MUST use global mode because we aren't guaranteed to get `start_supervised`'s pid back fast enough to `allow` it to
  # use expectations and stubs from test's pid.
  setup :set_mox_global

  setup :verify_on_exit!

  setup do
    start_supervised!({Task.Supervisor, name: Indexer.TaskSupervisor})

    :ok
  end

  describe "async_fetch/1" do
    # geth test node on circle ci is synced farther than Nethermind
    @tag :no_nethermind
    test "fetched codes for address_hashes", %{json_rpc_named_arguments: json_rpc_named_arguments} do
      variant = Keyword.fetch!(json_rpc_named_arguments, :variant)

      %{block_number: block_number, code: code, address: address, hash: hash} =
        case variant do
          EthereumJSONRPC.Geth ->
            %{
              block_number: 1_000_071,
              code:
                "0x3660008037602060003660003473273930d21e01ee25e4c219b63259d214872220a261235a5a03f21560015760206000f3",
              address: %Explorer.Chain.Hash{
                byte_count: 20,
                bytes: <<0x4615CC10092B514258577DAFCA98C142577F1578::big-integer-size(20)-unit(8)>>
              },
              hash: %Explorer.Chain.Hash{
                byte_count: 32,
                bytes:
                  <<0x9FC76417374AA880D4449A1F7F31EC597F00B1F6F3DD2D66F4C9C6C445836D8B::big-integer-size(32)-unit(8)>>
              }
            }

          EthereumJSONRPC.Nethermind ->
            %{
              block_number: 348_179,
              code:
                "0x6060604052604051602080611bac83395060806040819052905160008054600160a060020a0319166c010000000000000000000000008084020417908190559091600160a060020a039091169061094c8061014c8339908101919091526040519081900360a001906000f08015610002576001805480820180835582908280158290116100ad576000838152602090206100ad9181019083015b808211156101485760008155600101610099565b50505081548110156100025760009182526020909120018054600160a060020a0319166c010000000000000000000000009283029290920491909117905560018054600019810190811015610002576000918252602082200154604051600160a060020a03909116917feae903e3f0a84c029ee7c3800ed2d89e93face9257c349d8d88d164337b2f0be91a25061111480610a986000396000f35b509056606060405260405160208061094c83395060806040525180600080546c0100000000000000000000000080840204600160a060020a031990911617905550600180546c010000000000000000000000003381810291909104600160a060020a03199092169190911790915543600255604051600160a060020a03909116907f9709d040ed4aab7028d46f8532940a2230d99b95e8e5dffd6c62c36919f3962290600090a25061089a806100b26000396000f3606060405236156100a35760e060020a60003504630cbb0f8381146100a85780632ce5c284146100b757806339464884146100d257806361064b5a146101015780639700659114610133578063a37ba32a14610141578063a69df4b514610164578063c7c0c5bf146101f7578063cd8ed6f614610299578063cf309012146102ca578063cfefb3d5146102e3578063ed6a6d2814610305578063f83d08ba14610313575b610002565b34610002576103246005545b90565b3461000257610336600654600160a060020a031615156100b4565b34610002576103246004356000600560005082815481101561000257600091825260209091200154905061015f565b346100025761034a60043560243560015460009081908190819033600160a060020a0390811691161461034c57610002565b346100025761032460035481565b34610002576103246004356000818152600460205260409020600101545b919050565b346100025761034a61050b335b6000805460408051602090810184905281517f8da5cb5b0000000000000000000000000000000000000000000000000000000081529151600160a060020a0390931692638da5cb5b92600480820193929182900301818787803b156100025760325a03f11561000257505060405151600160a060020a03848116911614915061015f9050565b346100025761034a6004356024356000610576335b60006003600060009054906101000a9004600160a060020a0316600160a060020a0316631ed454a5846000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100025760325a03f115610002575050604051519190911015905080610893575061089382610171565b3461000257610336600435602435604435600154600090819033600160a060020a0390811691161461069357610002565b346100025761033660065460ff60a060020a9091041681565b346100025761032460043560008181526004602052604090206003015461015f565b346100025761032460025481565b346100025761034a6108233361020c565b60408051918252519081900360200190f35b604080519115158252519081900360200190f35b005b600654600160a060020a03161561036257610002565b6006805473ffffffffffffffffffffffffffffffffffffffff19166c0100000000000000000000000088810204179055600093505b6005548410156103e557600580548590811015610002579060005260206000209001600050546000818152600460205260409020600181015491945092509050848111156104445784610446565b436003819055600254604080518881526020810192909252818101929092529051600160a060020a038816917f593f3a6ca687633736d25531fb6f6fc7bd990ef6f1b7fb2c69cdf35a246e372e919081900360600190a2505050505050565b805b600183018190556006546040805160006020918201819052825160e060020a63e2b863cf0281526004810189905260248101959095529151600160a060020a039093169363e2b863cf9360448083019491928390030190829087803b156100025760325a03f11561000257505060408051805160038601819055600186015485835260208301528183015290518592507fe6ce162265809f487ca530c8f318b648987fd7dfec923edcc424d43ff53ffbb79181900360600190a2600190930192610397565b151561051657610002565b6006805474ff00000000000000000000000000000000000000001916908190556040805160a060020a90920460ff1615158252517fe85392445b5aa5368f61c68ea222f92bf5526e9f871142576e9a55dde7b56f0e9181900360200190a1565b151561058157610002565b600654600160a060020a0316151561059857610002565b60065460a060020a900460ff16156105af57610002565b60008381526004602052604090205460ff1615156105cc57610002565b5060008281526004602081815260408084206001810186905560065482518401869052825160e060020a63e2b863cf0281529485018890526024850187905291519094600160a060020a039092169363e2b863cf936044808301949193928390030190829087803b156100025760325a03f1156100025750506040805180516003850181905560018501548252602082015281518693507f5e763377c074567f93d6dbd49375bcea31d0ad895345b0ffa9aaed6f11106fbf929181900390910190a2505050565b600654600160a060020a0316156106a957610002565b6000831280156106cd57506000858152600460205260408120600101549084900390105b15610788576000858152600460209081526040918290206001015482519081529081018590528151869288927f842b8efac3852ccf2dc466623aa8eeaea245436ed889aa2ed22b8689997a7875929081900390910190a360009150610780565b600181018054840190555b60018101546040805185815260208101929092528051869288927fd9d0b091aebb6b491de28bb7faa8691ab87deafdb5753a532063f347052ff08e92918290030190a3600191505b509392505050565b506000848152600460205260409020805460ff16151561080257805460ff1916600190811782556005805491820180825590919082818380158290116107ef576000838152602090206107ef9181019083015b8082111561081f57600081556001016107db565b5050506000928352506020909120018590555b600083121561072d57600181018054600085900390039055610738565b5090565b151561082e57610002565b6006805474ff0000000000000000000000000000000000000000191660a060020a90811791829055604080519190920460ff161515815290517fe85392445b5aa5368f61c68ea222f92bf5526e9f871142576e9a55dde7b56f0e9181900360200190a1565b905061015f56606060405236156100565760e060020a60003504630a883790811461005b578063114d081d146100755780635632b1fa1461019e578063701b4631146101d05780639081c3db14610227578063d940c3ee146102b4575b610002565b346100025760015460408051918252519081900360200190f35b34610002576103556004356024356044355b600060006103873360006001600060009054906101000a9004600160a060020a0316600160a060020a0316631ed454a5846000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100025760325a03f1156100025750506040515191909110159050806107c057506107c0825b6000805460408051602090810184905281517f8da5cb5b0000000000000000000000000000000000000000000000000000000081529151600160a060020a0390931692638da5cb5b92600480820193929182900301818787803b156100025760325a03f11561000257505060405151600160a060020a0384811691161491506107c39050565b346100025761035760043560018054829081101561000257600091825260209091200154600160a060020a0316905081565b3461000257610373600435600060005b6001548110156105b85782600160a060020a0316600160005082815481101561000257600091825260209091200154600160a060020a031614156105c357600191506105bd565b34610002576103556004356024356105cb600060009054906101000a9004600160a060020a0316600160a060020a031663a313c371336000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100025760325a03f1156100025750506040515190508383610087565b346100025761035560043560243560006105cf3360006003600060009054906101000a9004600160a060020a0316600160a060020a0316631ed454a5846000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100025760325a03f1156100025750506040515191909110159050806107c057506107c082610118565b005b60408051600160a060020a039092168252519081900360200190f35b604080519115158252519081900360200190f35b151561039257610002565b6104233360006002600060009054906101000a9004600160a060020a0316600160a060020a0316631ed454a5846000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100025760325a03f1156100025750506040515191909110159050806107c057506107c082610118565b1580156104ad57506000805460408051602090810184905281517fa313c371000000000000000000000000000000000000000000000000000000008152600160a060020a03338116600483015292518a95939094169363a313c37193602480840194938390030190829087803b156100025760325a03f11561000257505060405151919091141590505b156104b757610002565b8215156104c357610002565b8415156104cf57610002565b6001805460001981019081101561000257600091825260208083209091015460408051830184905280517fcd8ed6f6000000000000000000000000000000000000000000000000000000008152600481018a905260248101899052604481018890529051600160a060020a039092169550859363cd8ed6f69360648084019491939192918390030190829087803b156100025760325a03f1156100025750506040805180518682528015156020830152825190945087935088927f2d7ae08615cc9f1cb489c18c1606e2e8fa626d00326c56964651002a5ad7f6fa928290030190a35050505050565b600091505b50919050565b6001016101e0565b5050565b15156105da57610002565b60018054600019810190811015610002576000918252602082200154604080517f61064b5a000000000000000000000000000000000000000000000000000000008152600160a060020a03878116600483015260248201879052915191909216935083926361064b5a926044808201939182900301818387803b156100025760325a03f115610002575050604080518481529051600160a060020a03841692507f7dd94d6391a4ae248774bfad14bcea2fec2615a379bfb8959fb0be5a9cc16d409181900360200190a2604051600054600160a060020a03169061094c806107c88339018082600160a060020a03168152602001915050604051809103906000f080156100025760018054808201808355829082801582901161071e5760008381526020902061071e9181019083015b808211156107bc576000815560010161070a565b5050508154811015610002576000918252602090912001805473ffffffffffffffffffffffffffffffffffffffff19166c010000000000000000000000009283029290920491909117905560018054600019810190811015610002576000918252602082200154604051600160a060020a03909116917feae903e3f0a84c029ee7c3800ed2d89e93face9257c349d8d88d164337b2f0be91a2505050565b5090565b90505b91905056606060405260405160208061094c83395060806040525180600080546c0100000000000000000000000080840204600160a060020a031990911617905550600180546c010000000000000000000000003381810291909104600160a060020a03199092169190911790915543600255604051600160a060020a03909116907f9709d040ed4aab7028d46f8532940a2230d99b95e8e5dffd6c62c36919f3962290600090a25061089a806100b26000396000f3606060405236156100a35760e060020a60003504630cbb0f8381146100a85780632ce5c284146100b757806339464884146100d257806361064b5a146101015780639700659114610133578063a37ba32a14610141578063a69df4b514610164578063c7c0c5bf146101f7578063cd8ed6f614610299578063cf309012146102ca578063cfefb3d5146102e3578063ed6a6d2814610305578063f83d08ba14610313575b610002565b34610002576103246005545b90565b3461000257610336600654600160a060020a031615156100b4565b34610002576103246004356000600560005082815481101561000257600091825260209091200154905061015f565b346100025761034a60043560243560015460009081908190819033600160a060020a0390811691161461034c57610002565b346100025761032460035481565b34610002576103246004356000818152600460205260409020600101545b919050565b346100025761034a61050b335b6000805460408051602090810184905281517f8da5cb5b0000000000000000000000000000000000000000000000000000000081529151600160a060020a0390931692638da5cb5b92600480820193929182900301818787803b156100025760325a03f11561000257505060405151600160a060020a03848116911614915061015f9050565b346100025761034a6004356024356000610576335b60006003600060009054906101000a9004600160a060020a0316600160a060020a0316631ed454a5846000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100025760325a03f115610002575050604051519190911015905080610893575061089382610171565b3461000257610336600435602435604435600154600090819033600160a060020a0390811691161461069357610002565b346100025761033660065460ff60a060020a9091041681565b346100025761032460043560008181526004602052604090206003015461015f565b346100025761032460025481565b346100025761034a6108233361020c565b60408051918252519081900360200190f35b604080519115158252519081900360200190f35b005b600654600160a060020a03161561036257610002565b6006805473ffffffffffffffffffffffffffffffffffffffff19166c0100000000000000000000000088810204179055600093505b6005548410156103e557600580548590811015610002579060005260206000209001600050546000818152600460205260409020600181015491945092509050848111156104445784610446565b436003819055600254604080518881526020810192909252818101929092529051600160a060020a038816917f593f3a6ca687633736d25531fb6f6fc7bd990ef6f1b7fb2c69cdf35a246e372e919081900360600190a2505050505050565b805b600183018190556006546040805160006020918201819052825160e060020a63e2b863cf0281526004810189905260248101959095529151600160a060020a039093169363e2b863cf9360448083019491928390030190829087803b156100025760325a03f11561000257505060408051805160038601819055600186015485835260208301528183015290518592507fe6ce162265809f487ca530c8f318b648987fd7dfec923edcc424d43ff53ffbb79181900360600190a2600190930192610397565b151561051657610002565b6006805474ff00000000000000000000000000000000000000001916908190556040805160a060020a90920460ff1615158252517fe85392445b5aa5368f61c68ea222f92bf5526e9f871142576e9a55dde7b56f0e9181900360200190a1565b151561058157610002565b600654600160a060020a0316151561059857610002565b60065460a060020a900460ff16156105af57610002565b60008381526004602052604090205460ff1615156105cc57610002565b5060008281526004602081815260408084206001810186905560065482518401869052825160e060020a63e2b863cf0281529485018890526024850187905291519094600160a060020a039092169363e2b863cf936044808301949193928390030190829087803b156100025760325a03f1156100025750506040805180516003850181905560018501548252602082015281518693507f5e763377c074567f93d6dbd49375bcea31d0ad895345b0ffa9aaed6f11106fbf929181900390910190a2505050565b600654600160a060020a0316156106a957610002565b6000831280156106cd57506000858152600460205260408120600101549084900390105b15610788576000858152600460209081526040918290206001015482519081529081018590528151869288927f842b8efac3852ccf2dc466623aa8eeaea245436ed889aa2ed22b8689997a7875929081900390910190a360009150610780565b600181018054840190555b60018101546040805185815260208101929092528051869288927fd9d0b091aebb6b491de28bb7faa8691ab87deafdb5753a532063f347052ff08e92918290030190a3600191505b509392505050565b506000848152600460205260409020805460ff16151561080257805460ff1916600190811782556005805491820180825590919082818380158290116107ef576000838152602090206107ef9181019083015b8082111561081f57600081556001016107db565b5050506000928352506020909120018590555b600083121561072d57600181018054600085900390039055610738565b5090565b151561082e57610002565b6006805474ff0000000000000000000000000000000000000000191660a060020a90811791829055604080519190920460ff161515815290517fe85392445b5aa5368f61c68ea222f92bf5526e9f871142576e9a55dde7b56f0e9181900360200190a1565b905061015f56",
              address: %Explorer.Chain.Hash{
                byte_count: 20,
                bytes: <<0x2458FA37D7D81E05A65180195413D1DB25F761E5::big-integer-size(20)-unit(8)>>
              },
              hash: %Explorer.Chain.Hash{
                byte_count: 32,
                bytes:
                  <<0x9FC76417374AA880D4449A1F7F31EC597F00B1F6F3DD2D66F4C9C6C445836D8B::big-integer-size(32)-unit(8)>>
              }
            }

          variant ->
            raise ArgumentError, "Unsupported variant (#{variant})"
        end

      if json_rpc_named_arguments[:transport] == EthereumJSONRPC.Mox do
        block_quantity = integer_to_quantity(block_number)
        address = to_string(address)

        EthereumJSONRPC.Mox
        |> expect(:json_rpc, fn [%{id: id, method: "eth_getCode", params: [^address, ^block_quantity]}], _options ->
          {:ok, [%{id: id, result: code}]}
        end)
        |> expect(:json_rpc, fn [%{id: id, method: "eth_getBalance", params: [^address, ^block_quantity]}], _options ->
          {:ok, [%{id: id, result: "0x0"}]}
        end)
      end

      insert(:address, hash: address)
      insert(:transaction, hash: hash, created_contract_address_hash: address)

      ContractCode.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)

      assert :ok =
               ContractCode.async_fetch([
                 %{created_contract_address_hash: address, block_number: block_number, hash: hash}
               ])

      fetched_address =
        wait(fn ->
          Repo.one!(from(address in Address, where: address.hash == ^address and not is_nil(address.contract_code)))
        end)

      assert to_string(fetched_address.contract_code) == code
      assert fetched_address.fetched_coin_balance
      assert fetched_address.fetched_coin_balance_block_number == block_number

      updated_transaction = Repo.one!(from(transaction in Transaction, where: transaction.hash == ^hash))

      assert updated_transaction.created_contract_code_indexed_at
    end
  end

  defp wait(producer) do
    producer.()
  rescue
    Ecto.NoResultsError ->
      Process.sleep(100)
      wait(producer)
  end
end
