require "test_helper"
require "shared/mailer_test_helper"
require "webmock/minitest"
require "eth"
require "test_helpers/csrf_getter"

class Api::Nextv1::CryptoAddressForChannelsControllerTest < ActionDispatch::IntegrationTest
  include Devise::Test::IntegrationHelpers
  include CsrfGetter

  setup do
    ActionController::Base.allow_forgery_protection = true
    @channel = channels(:verified)
    @crypto_address = crypto_addresses(:eth_address)
    @publisher = publishers(:verified)
    sign_in @publisher
    @csrf_token = get_csrf_token

    Aws.config[:s3] = {
      region: "us-west-2",
      credentials: Aws::Credentials.new("akid", "secret"),
      endpoint: "http://localhost:8000",
      stub_responses: {
        list_buckets: {
          buckets: [name: "brave-production-ofac-addresses"]
        },
        list_objects: {
          contents: [{key: "MHgxOTk5ZWY1MjcwMGMzNGRlN2VjMmI2OGEyOGFhZmIzN2RiMGM1YWRl"}]
        }
      }
    }
  end

  def teardown
    ActionController::Base.allow_forgery_protection = false
  end

  test "should get index" do
    get "/api/nextv1/channels/#{@channel.id}/crypto_address_for_channels", headers: {"HTTP_ACCEPT" => "application/json", "X-CSRF-Token" => @csrf_token}
    assert_response :success
    assert_equal @crypto_address.crypto_address_for_channels.first, assigns(:crypto_addresses_for_channel).find(@crypto_address.id)
  end

  test "should create crypto address for channel" do
    signature = "agABpynouN8NTjAxZXk5fEpfKRRiQ1nfc813juxr8a71TRsXxetiKeLahSbJC8XJTyz684PKtXq28snBoSTPB2s"
    account_address = "36fsf2BR6KNpHPLo9VawfoWEBqncKRMUpxbi3JVBNFWA"
    chain = "SOL"
    message = "d1133a45-deed-4398-9f85-5df3864ca460"
    Rails.cache.write(message, @publisher.id)

    Util::CryptoUtils.expects(:verify_solana_address).with(signature, account_address, message, @publisher).returns(true)
    Api::Nextv1::CryptoAddressForChannelsController.any_instance.expects(:replace_crypto_address_for_channel).with(account_address, chain, @channel).returns(true)
    Api::Nextv1::CryptoAddressForChannelsController.any_instance.expects(:sanctioned?).with(account_address).returns(false)

    post "/api/nextv1/channels/#{@channel.id}/crypto_address_for_channels", params: {
      transaction_signature: signature,
      account_address: account_address,
      chain: chain,
      message: message
    }, headers: {"HTTP_ACCEPT" => "application/json", "X-CSRF-Token" => @csrf_token}

    assert_response :created
  end

  test "should return error when creating crypto address for channel with invalid verification" do
    signature = "3mAsCPAU88U3U4AplCrrPMuL8K3df3ydGoqaQRSXqgqzM2o1zpzsk2JU9uY8Z1oke7nSgCc1Lhaxu7K5sowt6Z6p"
    account_address = "36fsf2BR6KNpHPLo9VawfoWEBqncKRMUpxbi3JVBNFWA"
    chain = "SOL"
    message = "this is an arbitrary string"

    post "/api/nextv1/channels/#{@channel.id}/crypto_address_for_channels", params: {
      transaction_signature: signature,
      account_address: account_address,
      chain: chain,
      message: message
    }, headers: {"HTTP_ACCEPT" => "application/json", "X-CSRF-Token" => @csrf_token}

    assert_response :bad_request
    assert_equal ["message is invalid"], JSON.parse(response.body)["errors"]
  end

  test "should reject a crypto address on the sanctioned list" do
    signature = "3mAsCPAU88U3U4AplCrrPMuL8K3df3ydGoqaQRSXqgqzM2o1zpzsk2JU9uY8Z1oke7nSgCc1Lhaxu7K5sowt6Z6p"
    account_address = "0x1999ef52700c34de7ec2b68a28aafb37db0c5ade"
    chain = "ETH"
    message = "d1133a45-deed-4398-9f85-5df3864ca460"
    Rails.cache.write(message, @publisher.id)

    Util::CryptoUtils.expects(:verify_ethereum_address).with(signature, account_address, message, @publisher).returns(true)

    post "/api/nextv1/channels/#{@channel.id}/crypto_address_for_channels", params: {
      transaction_signature: signature,
      account_address: account_address,
      chain: chain,
      message: message
    }, headers: {"HTTP_ACCEPT" => "application/json", "X-CSRF-Token" => @csrf_token}

    assert_response :bad_request
    assert_equal [], JSON.parse(response.body)["errors"]
  end

  test "should change address for channel" do
    account_address = "0xbB3Ea1e03A2dC8Bd2777D5Ea886a55e3573E726e"
    chain = "ETH"

    Api::Nextv1::CryptoAddressForChannelsController.any_instance.expects(:replace_crypto_address_for_channel).with(account_address, chain, @channel).returns(true)

    post "/api/nextv1/channels/#{@channel.id}/crypto_address_for_channels/change_address", params: {
      address: account_address,
      chain: chain
    }, headers: {"HTTP_ACCEPT" => "application/json", "X-CSRF-Token" => @csrf_token}

    assert_response :success
  end

  test "should return error when changing address for channel with invalid parameters" do
    account_address = nil
    chain = "ETH"
    post "/api/nextv1/channels/#{@channel.id}/crypto_address_for_channels/change_address", params: {
      address: account_address,
      chain: chain
    }, headers: {"HTTP_ACCEPT" => "application/json", "X-CSRF-Token" => @csrf_token}

    assert_response :bad_request
    assert_equal "address could not be updated", JSON.parse(response.body)["errors"]
  end

  test "should verify Solana address" do
    signature = "agABpynouN8NTjAxZXk5fEpfKRRiQ1nfc813juxr8a71TRsXxetiKeLahSbJC8XJTyz684PKtXq28snBoSTPB2s"
    account_address = "36fsf2BR6KNpHPLo9VawfoWEBqncKRMUpxbi3JVBNFWA"
    message = "d1133a45-deed-4398-9f85-5df3864ca460"

    assert_equal true, Util::CryptoUtils.verify_solana_address(signature, account_address, message, @publisher)
  end

  test "should verify Ethereum address" do
    signature = "0xc6ed3f93f3ca79fc3ebd7548d4adb79ef70a5fbea35ed088ffe265389be4f65f4980e056316bedb515ffafe1dda3889f7e753c78d26dd16146e39ee7e62382021b"
    address = "0x3430E11a53fE270C0ce3997AfFf1Ba6F9B48b59F"
    message = "1686284137397"

    Eth::Signature.expects(:personal_recover).with(message, signature).returns(address)
    Eth::Util.expects(:public_key_to_address).with(address).returns(Eth::Address.new(address))

    assert_equal true, Util::CryptoUtils.verify_ethereum_address(signature, address, message, @publisher)
  end
end
