import { test as creditNoteTest } from '@/manager/modules/credit-note/credit-note-fixtures';
import { getInvoiceIssueCreditNoteData } from '@/manager/modules/invoice/invoice-factories';
import { test as invoiceTest } from '@/manager/modules/invoice/invoice-fixtures';
import { toInvoiceCreditNoteNumber } from '@/manager/modules/invoice/invoice-mappers';
import {
  expectDataTableColumnToContainText,
  expectDataTableTextColumnToHaveText,
} from '@/manager/modules/ui/data-table/data-table-assertions';
import { creditNoteTableColumnTestIds } from '@/manager/modules/ui/data-table/data/data-table-column-test-ids';
import { formatDate } from '@/shared/utils/formatters';
import { expect } from '@/shared/utils/matchers';
import { mergeTests } from '@playwright/test';

// The invoice fixtures provide the API setup (invoice + credit note), the credit-note fixtures the list page;
// no fixture names clash between the two modules.
const test = mergeTests(invoiceTest, creditNoteTest);

// Issuing waits for the invoice charge to settle before the credit note can be created — give the per-test
// budget headroom over the 30s default.
test.describe.configure({ mode: 'default', timeout: 120_000 });

test('filters by credit note number', async ({
  setupInvoiceCreateData,
  createInvoice,
  issueCreditNote,
  creditNoteListPage,
}) => {
  const data = await setupInvoiceCreateData({ numberOfProducts: 1 });
  const creditData = getInvoiceIssueCreditNoteData(data, { items: [{ productIndex: 0, selected: true }] });

  const invoice = await createInvoice(data);
  const creditNoteNumber = toInvoiceCreditNoteNumber(invoice);
  await issueCreditNote(invoice.id, creditData);

  await creditNoteListPage.goto();

  await test.step('apply filter', () => creditNoteListPage.searchTextField.fill(creditNoteNumber));

  await test.step('verify list is filtered', async () => {
    await expect(creditNoteListPage.dataTable.getRows()).toHaveCount(1);
    await expectDataTableTextColumnToHaveText(
      creditNoteListPage.dataTable,
      creditNoteTableColumnTestIds.id,
      creditNoteNumber
    );
  });
});

test('filters by location', async ({ setupInvoiceCreateData, createInvoice, issueCreditNote, creditNoteListPage }) => {
  const data = await setupInvoiceCreateData({ numberOfProducts: 1 });
  const creditData = getInvoiceIssueCreditNoteData(data, { items: [{ productIndex: 0, selected: true }] });

  const invoice = await createInvoice(data);
  await issueCreditNote(invoice.id, creditData);

  await creditNoteListPage.goto();

  await test.step('apply filter', () => creditNoteListPage.locationAutocomplete.fill([data.location.name]));

  await test.step('verify list is filtered', async () => {
    await expect(creditNoteListPage.dataTable.getRows()).toHaveCountGreaterThan(0);
    await expectDataTableColumnToContainText(
      creditNoteListPage.dataTable,
      creditNoteTableColumnTestIds.location,
      data.location.name
    );
  });
});

test('filters by created-at', async ({
  setupInvoiceCreateData,
  createInvoice,
  issueCreditNote,
  creditNoteListPage,
}) => {
  const data = await setupInvoiceCreateData({ numberOfProducts: 1 });
  const creditData = getInvoiceIssueCreditNoteData(data, { items: [{ productIndex: 0, selected: true }] });
  const today = new Date();

  const invoice = await createInvoice(data);
  await issueCreditNote(invoice.id, creditData);

  await creditNoteListPage.goto();

  await test.step('apply filter', () => creditNoteListPage.createdAtDatePicker.fill(today));

  await test.step('verify list is filtered', async () => {
    await expect(creditNoteListPage.dataTable.getRows()).toHaveCountGreaterThan(0);
    await expectDataTableColumnToContainText(
      creditNoteListPage.dataTable,
      creditNoteTableColumnTestIds.issueDate,
      formatDate(today, data.location.timezone)
    );
  });
});

test('filters by credit note number, location and created-at', async ({
  setupInvoiceCreateData,
  createInvoice,
  issueCreditNote,
  creditNoteListPage,
}) => {
  const data = await setupInvoiceCreateData({ numberOfProducts: 1 });
  const creditData = getInvoiceIssueCreditNoteData(data, { items: [{ productIndex: 0, selected: true }] });

  const invoice = await createInvoice(data);
  const creditNoteNumber = toInvoiceCreditNoteNumber(invoice);
  await issueCreditNote(invoice.id, creditData);

  await creditNoteListPage.goto();

  await test.step('apply filters', async () => {
    await creditNoteListPage.searchTextField.fill(creditNoteNumber);
    await creditNoteListPage.locationAutocomplete.fill([data.location.name]);
    await creditNoteListPage.createdAtDatePicker.fill(new Date());
  });

  await test.step('verify list is filtered', async () => {
    await expect(creditNoteListPage.dataTable.getRows()).toHaveCount(1);
    await expectDataTableTextColumnToHaveText(
      creditNoteListPage.dataTable,
      creditNoteTableColumnTestIds.id,
      creditNoteNumber
    );
    await expectDataTableColumnToContainText(
      creditNoteListPage.dataTable,
      creditNoteTableColumnTestIds.location,
      data.location.name
    );
  });
});

test('excludes credit notes that do not match the search filter', async ({
  setupInvoiceCreateData,
  createInvoice,
  issueCreditNote,
  creditNoteListPage,
}) => {
  const data = await setupInvoiceCreateData({ numberOfProducts: 1 });
  const creditData = getInvoiceIssueCreditNoteData(data, { items: [{ productIndex: 0, selected: true }] });

  const invoice = await createInvoice(data);
  await issueCreditNote(invoice.id, creditData);

  await creditNoteListPage.goto();

  // The invoice's credit note always carries the -CN-01 suffix, so this searches right past it.
  await test.step('apply filter', () => creditNoteListPage.searchTextField.fill(`${invoice.number}-CN-02`));

  await test.step('verify credit note is excluded', async () => {
    await expect(creditNoteListPage.dataTable.noDataRow).toBeVisible();
  });
});
