require "test_helper"

class EnableBankingItem::ImporterDedupTest < ActiveSupport::TestCase
  setup do
    @family = families(:dylan_family)
    @enable_banking_item = EnableBankingItem.create!(
      family: @family,
      name: "Test Enable Banking",
      country_code: "AT",
      application_id: "test_app_id",
      client_certificate: "test_cert",
      session_id: "test_session",
      session_expires_at: 1.day.from_now
    )

    mock_provider = mock()
    @importer = EnableBankingItem::Importer.new(@enable_banking_item, enable_banking_provider: mock_provider)
  end

  test "removes content-level duplicates with different entry_reference IDs" do
    transactions = [
      {
        entry_reference: "ref_aaa",
        transaction_id: nil,
        booking_date: "2026-02-07",
        transaction_amount: { amount: "11.65", currency: "EUR" },
        creditor: { name: "Spar Dankt 3418" },
        credit_debit_indicator: "DBIT",
        status: "BOOK"
      },
      {
        entry_reference: "ref_bbb",
        transaction_id: nil,
        booking_date: "2026-02-07",
        transaction_amount: { amount: "11.65", currency: "EUR" },
        creditor: { name: "Spar Dankt 3418" },
        credit_debit_indicator: "DBIT",
        status: "BOOK"
      }
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 1, result.count
    assert_equal "ref_aaa", result.first[:entry_reference]
  end

  test "keeps transactions with different amounts" do
    transactions = [
      {
        entry_reference: "ref_1",
        booking_date: "2026-02-07",
        transaction_amount: { amount: "11.65", currency: "EUR" },
        creditor: { name: "Spar" },
        status: "BOOK"
      },
      {
        entry_reference: "ref_2",
        booking_date: "2026-02-07",
        transaction_amount: { amount: "23.30", currency: "EUR" },
        creditor: { name: "Spar" },
        status: "BOOK"
      }
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 2, result.count
  end

  test "keeps transactions with different dates" do
    transactions = [
      {
        entry_reference: "ref_1",
        booking_date: "2026-02-07",
        transaction_amount: { amount: "11.65", currency: "EUR" },
        creditor: { name: "Spar" },
        status: "BOOK"
      },
      {
        entry_reference: "ref_2",
        booking_date: "2026-02-08",
        transaction_amount: { amount: "11.65", currency: "EUR" },
        creditor: { name: "Spar" },
        status: "BOOK"
      }
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 2, result.count
  end

  test "keeps transactions with different creditors" do
    transactions = [
      {
        entry_reference: "ref_1",
        booking_date: "2026-02-07",
        transaction_amount: { amount: "11.65", currency: "EUR" },
        creditor: { name: "Spar" },
        status: "BOOK"
      },
      {
        entry_reference: "ref_2",
        booking_date: "2026-02-07",
        transaction_amount: { amount: "11.65", currency: "EUR" },
        creditor: { name: "Lidl" },
        status: "BOOK"
      }
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 2, result.count
  end

  test "removes multiple duplicates from same response" do
    base = {
      booking_date: "2026-02-07",
      transaction_amount: { amount: "3.00", currency: "EUR" },
      creditor: { name: "Bakery" },
      status: "BOOK"
    }

    transactions = [
      base.merge(entry_reference: "ref_1"),
      base.merge(entry_reference: "ref_2"),
      base.merge(entry_reference: "ref_3")
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 1, result.count
    assert_equal "ref_1", result.first[:entry_reference]
  end

  test "handles string keys in transaction data" do
    transactions = [
      {
        "entry_reference" => "ref_aaa",
        "booking_date" => "2026-02-07",
        "transaction_amount" => { "amount" => "11.65", "currency" => "EUR" },
        "creditor" => { "name" => "Spar" },
        "status" => "BOOK"
      },
      {
        "entry_reference" => "ref_bbb",
        "booking_date" => "2026-02-07",
        "transaction_amount" => { "amount" => "11.65", "currency" => "EUR" },
        "creditor" => { "name" => "Spar" },
        "status" => "BOOK"
      }
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 1, result.count
  end

  test "differentiates by remittance_information" do
    transactions = [
      {
        entry_reference: "ref_1",
        booking_date: "2026-02-07",
        transaction_amount: { amount: "100.00", currency: "EUR" },
        creditor: { name: "Landlord" },
        remittance_information: [ "Rent January" ],
        status: "BOOK"
      },
      {
        entry_reference: "ref_2",
        booking_date: "2026-02-07",
        transaction_amount: { amount: "100.00", currency: "EUR" },
        creditor: { name: "Landlord" },
        remittance_information: [ "Rent February" ],
        status: "BOOK"
      }
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 2, result.count
  end

  test "handles nil values in remittance_information array" do
    transactions = [
      {
        entry_reference: "ref_aaa",
        booking_date: "2026-02-07",
        transaction_amount: { amount: "11.65", currency: "EUR" },
        creditor: { name: "Spar" },
        remittance_information: [ nil, "Payment ref 123", nil ],
        status: "BOOK"
      },
      {
        entry_reference: "ref_bbb",
        booking_date: "2026-02-07",
        transaction_amount: { amount: "11.65", currency: "EUR" },
        creditor: { name: "Spar" },
        remittance_information: [ "Payment ref 123", nil ],
        status: "BOOK"
      }
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 1, result.count
    assert_equal "ref_aaa", result.first[:entry_reference]
  end

  test "preserves distinct transactions with same content but different transaction_ids" do
    transactions = [
      {
        entry_reference: "ref_1",
        transaction_id: "txn_001",
        booking_date: "2026-02-09",
        transaction_amount: { amount: "1.50", currency: "EUR" },
        creditor: { name: "Waschsalon" },
        status: "BOOK"
      },
      {
        entry_reference: "ref_2",
        transaction_id: "txn_002",
        booking_date: "2026-02-09",
        transaction_amount: { amount: "1.50", currency: "EUR" },
        creditor: { name: "Waschsalon" },
        status: "BOOK"
      }
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 2, result.count
  end

  test "deduplicates same transaction_id even with different entry_references" do
    transactions = [
      {
        entry_reference: "ref_aaa",
        transaction_id: "txn_same",
        booking_date: "2026-02-09",
        transaction_amount: { amount: "25.00", currency: "EUR" },
        creditor: { name: "Amazon" },
        status: "BOOK"
      },
      {
        entry_reference: "ref_bbb",
        transaction_id: "txn_same",
        booking_date: "2026-02-09",
        transaction_amount: { amount: "25.00", currency: "EUR" },
        creditor: { name: "Amazon" },
        status: "BOOK"
      }
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 1, result.count
    assert_equal "ref_aaa", result.first[:entry_reference]
  end

  test "preserves transactions with same non-unique transaction_id but different content" do
    # Per Enable Banking API docs, transaction_id is not guaranteed to be unique.
    # Two transactions sharing a transaction_id but differing in content must both be kept.
    transactions = [
      {
        entry_reference: "ref_1",
        transaction_id: "shared_tid",
        booking_date: "2026-02-09",
        transaction_amount: { amount: "25.00", currency: "EUR" },
        creditor: { name: "Amazon" },
        status: "BOOK"
      },
      {
        entry_reference: "ref_2",
        transaction_id: "shared_tid",
        booking_date: "2026-02-09",
        transaction_amount: { amount: "42.00", currency: "EUR" },
        creditor: { name: "Amazon" },
        status: "BOOK"
      }
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 2, result.count
  end

  test "deduplicates using value_date when booking_date is absent" do
    transactions = [
      {
        entry_reference: "ref_1",
        transaction_id: nil,
        value_date: "2026-02-10",
        transaction_amount: { amount: "1.50", currency: "EUR" },
        creditor: { name: "Waschsalon" },
        status: "BOOK"
      },
      {
        entry_reference: "ref_2",
        transaction_id: nil,
        value_date: "2026-02-10",
        transaction_amount: { amount: "1.50", currency: "EUR" },
        creditor: { name: "Waschsalon" },
        status: "BOOK"
      }
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 1, result.count
    assert_equal "ref_1", result.first[:entry_reference]
  end

  test "keeps payment and same-day refund with same amount as separate transactions" do
    transactions = [
      {
        entry_reference: "ref_payment",
        transaction_id: nil,
        booking_date: "2026-02-09",
        transaction_amount: { amount: "25.00", currency: "EUR" },
        creditor: { name: "Amazon" },
        credit_debit_indicator: "DBIT",
        status: "BOOK"
      },
      {
        entry_reference: "ref_refund",
        transaction_id: nil,
        booking_date: "2026-02-09",
        transaction_amount: { amount: "25.00", currency: "EUR" },
        creditor: { name: "Amazon" },
        credit_debit_indicator: "CRDT",
        status: "BOOK"
      }
    ]

    result = @importer.send(:deduplicate_api_transactions, transactions)

    assert_equal 2, result.count
  end

  test "returns empty array for empty input" do
    result = @importer.send(:deduplicate_api_transactions, [])
    assert_equal [], result
  end
end
