import { getCustomerCreateData } from '@/manager/modules/customer/customer-factories';
import { test } from '@/manager/modules/customer/customer-fixtures';
import { formatCustomerName } from '@/manager/modules/customer/customer-utils';
import { customerCreateHappyTestCases } from '@/manager/modules/customer/test-cases/customer-create-happy-test-cases';
import {
  expectDataTableChipsColumnToHaveText,
  expectDataTableTextColumnToHaveText,
} from '@/manager/modules/ui/data-table/data-table-assertions';
import { customerTableColumnTestIds } from '@/manager/modules/ui/data-table/data/data-table-column-test-ids';
import { expectMultiLocatorToHaveText, expectSingleLocatorToHaveText } from '@/manager/shared/utils/expect-utils';
import { vatTypes } from '@/shared/data/seed-vat-types';
import { formatAddress, formatCurrency, formatDate, formatPhone } from '@/shared/utils/formatters';
import { expect } from '@/shared/utils/matchers';

for (const tc of customerCreateHappyTestCases) {
  test(tc.description, async ({ customerCreateDialog, trackCustomerForTeardown }) => {
    const data = getCustomerCreateData(tc.options);
    const customerFullName = formatCustomerName(data.firstName, data.lastName);
    const customerTitle = data.type === 'business' ? data.companyName : customerFullName;
    const customerPhone = formatPhone(data.phone);
    const customerAddress = formatAddress(data.street, data.postalCode, data.city, data.country.name);
    const customerStatus = 'lead';
    const customerCreatedAt = formatDate(new Date());
    const customerCurrency = data.locations[0].currency;
    const customerLocationNames = data.locations.map((l) => l.name);
    const zeroAmount = formatCurrency(0, customerCurrency);

    await customerCreateDialog.goto();

    const detailsPage = await test.step('create customer', () => customerCreateDialog.create(data));

    trackCustomerForTeardown(detailsPage.getCustomerId());

    await test.step('verify new customer on details page', async () => {
      await expectSingleLocatorToHaveText(detailsPage.title, customerTitle);
      await expectSingleLocatorToHaveText(detailsPage.status, customerStatus);
      await expectMultiLocatorToHaveText(detailsPage.generalCard.locations, customerLocationNames);
      await expectSingleLocatorToHaveText(detailsPage.generalCard.type, data.type);

      if (data.type === 'business') {
        await expectSingleLocatorToHaveText(detailsPage.generalCard.companyName, data.companyName);
        await expectSingleLocatorToHaveText(detailsPage.generalCard.vatType, data.vatType?.name);
        await expectSingleLocatorToHaveText(detailsPage.generalCard.vatNumber, data.vatNumber);
      } else {
        await expect(detailsPage.generalCard.companyName).toBeHidden();
        await expect(detailsPage.generalCard.vatType).toBeHidden();
        await expect(detailsPage.generalCard.vatNumber).toBeHidden();
      }

      await expectSingleLocatorToHaveText(detailsPage.generalCard.name, customerFullName);
      await expectSingleLocatorToHaveText(detailsPage.generalCard.email, data.email);
      await expectSingleLocatorToHaveText(detailsPage.generalCard.phoneNumber, customerPhone);
      await expectSingleLocatorToHaveText(detailsPage.generalCard.language, data.language.id);
      await expectSingleLocatorToHaveText(detailsPage.generalCard.address, customerAddress);
      await expectSingleLocatorToHaveText(detailsPage.generalCard.note, data.note);

      await expect(detailsPage.detailsCard.customerId).not.toBeEmpty();
      await expectSingleLocatorToHaveText(detailsPage.detailsCard.createdAt, customerCreatedAt);
      await expectSingleLocatorToHaveText(detailsPage.detailsCard.totalSpent, zeroAmount);
      await expectSingleLocatorToHaveText(detailsPage.detailsCard.totalPastDueAmount, zeroAmount);
      await expect(detailsPage.detailsCard.paymentMethods).toHaveCount(0);
      await expectSingleLocatorToHaveText(
        detailsPage.detailsCard.accountsReceivableNumber,
        data.accountsReceivableNumber
      );

      await expect(detailsPage.bookingsCard.main).toBeHidden();
      await expect(detailsPage.invoicesCard.main).toBeHidden();
    });

    await test.step('verify new customer on list page', async () => {
      const listPage = await detailsPage.returnToCustomerListPage();

      await listPage.searchTextField.fill(data.email);

      await expect(listPage.dataTable.getRows()).toHaveCount(1);
      await expect(listPage.dataTable.getRowColumn(0, customerTableColumnTestIds.id)).not.toBeEmpty();
      await expectDataTableTextColumnToHaveText(listPage.dataTable, customerTableColumnTestIds.name, customerTitle);
      await expectDataTableChipsColumnToHaveText(
        listPage.dataTable,
        customerTableColumnTestIds.locations,
        customerLocationNames
      );
      await expectDataTableTextColumnToHaveText(listPage.dataTable, customerTableColumnTestIds.email, data.email);
      await expectDataTableTextColumnToHaveText(
        listPage.dataTable,
        customerTableColumnTestIds.phoneNumber,
        customerPhone
      );
      await expectDataTableChipsColumnToHaveText(listPage.dataTable, customerTableColumnTestIds.status, customerStatus);
      await expectDataTableChipsColumnToHaveText(
        listPage.dataTable,
        customerTableColumnTestIds.hasPastDueInvoices,
        'none'
      );
      await expectDataTableTextColumnToHaveText(
        listPage.dataTable,
        customerTableColumnTestIds.createdAt,
        customerCreatedAt
      );
    });
  });
}

test('rejects a private customer without all required fields', async ({ customerCreateDialog }) => {
  const data = getCustomerCreateData({ type: 'private', firstName: '', lastName: '' });

  await customerCreateDialog.goto();

  await test.step('submit invalid customer create form', async () => {
    await customerCreateDialog.fill(data);
    await customerCreateDialog.submit();
  });

  await test.step('verify errors on form', async () => {
    await expect(customerCreateDialog.errors).toHaveCountGreaterThan(0);
  });
});

test('rejects a business customer without all required fields', async ({ customerCreateDialog }) => {
  const data = getCustomerCreateData({ type: 'business', companyName: '' });

  await customerCreateDialog.goto();

  await test.step('submit invalid customer create form', async () => {
    await customerCreateDialog.fill(data);
    await customerCreateDialog.submit();
  });

  await test.step('verify errors on form', async () => {
    await expect(customerCreateDialog.errors).toHaveCountGreaterThan(0);
  });
});

test('rejects a customer with a duplicate email', async ({ createCustomer, customerCreateDialog }) => {
  const existing = await createCustomer(getCustomerCreateData());
  const data = getCustomerCreateData({ email: existing.email });

  await customerCreateDialog.goto();

  await test.step('submit customer create form with duplicate email', async () => {
    await customerCreateDialog.fill(data);
    await customerCreateDialog.submit();
  });

  await test.step('verify errors on form', async () => {
    await expect(customerCreateDialog.errors).toHaveCountGreaterThan(0);
  });
});

test('rejects a customer with a duplicate phone number', async ({ createCustomer, customerCreateDialog }) => {
  const existing = await createCustomer(getCustomerCreateData());
  const data = getCustomerCreateData({ phone: existing.phone, country: existing.country });

  await customerCreateDialog.goto();

  await test.step('submit customer create form with duplicate phone number', async () => {
    await customerCreateDialog.fill(data);
    await customerCreateDialog.submit();
  });

  await test.step('verify errors on form', async () => {
    await expect(customerCreateDialog.errors).toHaveCountGreaterThan(0);
  });
});

test('rejects a customer with a vat number that does not match the vat type', async ({ customerCreateDialog }) => {
  const data = getCustomerCreateData({
    type: 'business',
    vatType: vatTypes.eu_vat,
    vatNumber: 'INVALID-VAT-1234',
  });

  await customerCreateDialog.goto();

  await test.step('submit customer create form with mismatched vat type and number', async () => {
    await customerCreateDialog.fill(data);
    await customerCreateDialog.submit();
  });

  await test.step('verify errors on form', async () => {
    await expect(customerCreateDialog.errors).toHaveCountGreaterThan(0);
  });
});
