import { test as creditNoteTest } from '@/manager/modules/credit-note/credit-note-fixtures';
import { getCustomerDisplayName } from '@/manager/modules/customer/customer-utils';
import { getInvoiceIssueCreditNoteData } from '@/manager/modules/invoice/invoice-factories';
import { test as invoiceTest } from '@/manager/modules/invoice/invoice-fixtures';
import {
  toInvoiceCreditNoteNumber,
  toInvoiceIssueCreditNoteTotalsSummary,
} from '@/manager/modules/invoice/invoice-mappers';
import { formatCurrency } from '@/shared/utils/formatters';
import { expect } from '@/shared/utils/matchers';
import { readPdfText, toPdfText } from '@/shared/utils/pdf-utils';
import { pollOrSkip } from '@/shared/utils/poll-utils';
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('downloads the credit note pdf from the list', async ({
  page,
  setupInvoiceCreateData,
  createInvoice,
  issueCreditNote,
  creditNoteListPage,
}) => {
  const data = await setupInvoiceCreateData({ numberOfProducts: 1 });
  const creditData = getInvoiceIssueCreditNoteData(data, { items: [{ productIndex: 0, selected: true }] });
  const customerName = getCustomerDisplayName(data.customer);
  // The storeroom Stripe account renders its documents in German, so the PDF total is German-formatted.
  const amount = formatCurrency(
    toInvoiceIssueCreditNoteTotalsSummary(creditData).totalInclVat,
    data.location.currency,
    'de-DE'
  );

  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));

  // The row's download button only renders once the credit note pdf has synced from Stripe — reload-poll until
  // it shows up. The applied filter persists across reloads (grid filters live in localStorage), so the row
  // under test stays the only one.
  await test.step('wait for the credit note pdf to sync', () =>
    pollOrSkip(
      async () => {
        await creditNoteListPage.reload();
        await expect(creditNoteListPage.dataTable.getRows()).toHaveCount(1);
        await expect(creditNoteListPage.getDownloadButton(0)).toBeVisible();
      },
      { timeout: 60_000, reason: 'credit note pdf did not sync from Stripe within 60s — async pdf download job' }
    ));

  const download = await test.step('download credit note pdf', async () => {
    // The button fetches a signed Kinnovis storage link and opens it in a new tab that immediately turns into a
    // file download and closes itself — Chromium attributes that download to the opener page, so listen there.
    const [creditNotePdfDownload] = await Promise.all([
      page.waitForEvent('download'),
      creditNoteListPage.getDownloadButton(0).click(),
    ]);

    return creditNotePdfDownload;
  });

  await test.step('verify credit note pdf contents', async () => {
    const pdfText = await readPdfText(await download.path());

    expect(pdfText).toContain(toPdfText(creditNoteNumber));
    expect(pdfText).toContain(toPdfText(invoice.number));
    expect(pdfText).toContain(toPdfText(customerName));
    expect(pdfText).toContain(toPdfText(creditData.reason));
    expect(pdfText).toContain(toPdfText(amount));
  });
});
