require "test_helper"

class CoinstatsItemsControllerTest < ActionDispatch::IntegrationTest
  setup do
    sign_in users(:family_admin)
    @family = families(:dylan_family)
    @coinstats_item = CoinstatsItem.create!(
      family: @family,
      name: "Test CoinStats Connection",
      api_key: "test_api_key_123"
    )
    tailwind_build = Rails.root.join("app/assets/builds/tailwind.css")
    FileUtils.mkdir_p(tailwind_build.dirname)
    File.write(tailwind_build, "/* test */") unless tailwind_build.exist?
  end

  # Helper to wrap data in Provider::Response
  def success_response(data)
    Provider::Response.new(success?: true, data: data, error: nil)
  end

  def error_response(message)
    Provider::Response.new(success?: false, data: nil, error: Provider::Error.new(message))
  end

  test "should get new" do
    get new_coinstats_item_url
    assert_response :success
  end

  test "should create coinstats item with valid api key" do
    # Mock the API key validation
    Provider::Coinstats.any_instance.expects(:get_blockchains).returns(success_response([])).once

    assert_difference("CoinstatsItem.count", 1) do
      post coinstats_items_url, params: {
        coinstats_item: {
          name: "New CoinStats Connection",
          api_key: "valid_api_key"
        }
      }
    end
  end

  test "should not create coinstats item with invalid api key" do
    # Mock the API key validation to fail
    Provider::Coinstats.any_instance.expects(:get_blockchains)
      .returns(error_response("Invalid API key"))

    assert_no_difference("CoinstatsItem.count") do
      post coinstats_items_url, params: {
        coinstats_item: {
          name: "New CoinStats Connection",
          api_key: "invalid_api_key"
        }
      }
    end
  end

  test "should destroy coinstats item" do
    # Schedules for deletion, doesn't actually delete immediately
    assert_no_difference("CoinstatsItem.count") do
      delete coinstats_item_url(@coinstats_item)
    end

    assert_redirected_to settings_providers_path
    @coinstats_item.reload
    assert @coinstats_item.scheduled_for_deletion?
  end

  test "should sync coinstats item" do
    post sync_coinstats_item_url(@coinstats_item)
    assert_redirected_to accounts_path
  end

  test "sync responds to json format" do
    post sync_coinstats_item_url(@coinstats_item, format: :json)
    assert_response :ok
  end

  test "should update coinstats item with valid api key" do
    Provider::Coinstats.any_instance.expects(:get_blockchains).returns(success_response([])).once

    patch coinstats_item_url(@coinstats_item), params: {
      coinstats_item: {
        name: "Updated Name",
        api_key: "new_valid_api_key"
      }
    }

    @coinstats_item.reload
    assert_equal "Updated Name", @coinstats_item.name
  end

  test "should not update coinstats item with invalid api key" do
    Provider::Coinstats.any_instance.expects(:get_blockchains)
      .returns(error_response("Invalid API key"))

    original_name = @coinstats_item.name

    patch coinstats_item_url(@coinstats_item), params: {
      coinstats_item: {
        name: "Updated Name",
        api_key: "invalid_api_key"
      }
    }

    @coinstats_item.reload
    assert_equal original_name, @coinstats_item.name
  end

  test "link_wallet requires all parameters" do
    post link_wallet_coinstats_items_url, params: {
      coinstats_item_id: @coinstats_item.id,
      address: "0x123"
      # missing blockchain
    }

    assert_response :unprocessable_entity
  end

  test "link_wallet with valid params creates accounts" do
    balance_data = [
      { coinId: "ethereum", name: "Ethereum", symbol: "ETH", amount: 1.5, price: 2000 }
    ]

    bulk_response = [
      { blockchain: "ethereum", address: "0x123abc", connectionId: "ethereum", balances: balance_data }
    ]

    Provider::Coinstats.any_instance.expects(:get_wallet_balances)
      .with("ethereum:0x123abc")
      .returns(success_response(bulk_response))

    Provider::Coinstats.any_instance.expects(:extract_wallet_balance)
      .with(bulk_response, "0x123abc", "ethereum")
      .returns(balance_data)

    assert_difference("Account.count", 1) do
      assert_difference("CoinstatsAccount.count", 1) do
        post link_wallet_coinstats_items_url, params: {
          coinstats_item_id: @coinstats_item.id,
          address: "0x123abc",
          blockchain: "ethereum"
        }
      end
    end

    assert_redirected_to accounts_path
  end

  test "link_wallet handles provider errors" do
    Provider::Coinstats.any_instance.expects(:get_wallet_balances)
      .raises(Provider::Coinstats::Error.new("Invalid API key"))

    post link_wallet_coinstats_items_url, params: {
      coinstats_item_id: @coinstats_item.id,
      address: "0x123abc",
      blockchain: "ethereum"
    }

    assert_response :unprocessable_entity
  end

  test "link_wallet handles no tokens found" do
    Provider::Coinstats.any_instance.expects(:get_wallet_balances)
      .returns(success_response([]))

    Provider::Coinstats.any_instance.expects(:extract_wallet_balance)
      .returns([])

    post link_wallet_coinstats_items_url, params: {
      coinstats_item_id: @coinstats_item.id,
      address: "0x123abc",
      blockchain: "ethereum"
    }

    assert_response :unprocessable_entity
    assert_match(/No tokens found/, response.body)
  end

  test "link_exchange filters unexpected connection fields" do
    Provider::Coinstats.any_instance.expects(:get_exchanges).returns(success_response([
      {
        connectionId: "bitvavo",
        name: "Bitvavo",
        connectionFields: [
          { key: "apiKey", name: "API Key" },
          { key: "apiSecret", name: "API Secret" }
        ]
      }
    ])).once

    linker_result = CoinstatsItem::ExchangeLinker::Result.new(success?: true, created_count: 0, errors: [])
    CoinstatsItem::ExchangeLinker.expects(:new).with(
      @coinstats_item,
      connection_id: "bitvavo",
      connection_fields: { "apiKey" => "key", "apiSecret" => "secret" },
      name: "Bitvavo"
    ).returns(stub(link: linker_result))

    post link_exchange_coinstats_items_url, params: {
      coinstats_item_id: @coinstats_item.id,
      exchange_connection_id: "bitvavo",
      exchange_connection_name: "Bitvavo",
      connection_fields: {
        apiKey: " key ",
        apiSecret: " secret ",
        unexpected: "should_not_be_forwarded"
      }
    }

    assert_redirected_to accounts_path
  end
end
