import { getInsuranceCreateData } from '@/manager/modules/insurance/insurance-factories';
import { test } from '@/manager/modules/insurance/insurance-fixtures';
import { insuranceCreateBookingPlanUnhappyTestCases } from '@/manager/modules/insurance/test-cases/insurance-create-booking-plan-unhappy-test-cases';
import { insuranceCreateHappyTestCases } from '@/manager/modules/insurance/test-cases/insurance-create-happy-test-cases';
import { insuranceCreateUnhappyTestCases } from '@/manager/modules/insurance/test-cases/insurance-create-unhappy-test-cases';
import { verifyBookingPlansTable } from '@/manager/modules/ui/booking-plan/booking-plan-assertions';
import { expectDataTableTextColumnToHaveText } from '@/manager/modules/ui/data-table/data-table-assertions';
import { insuranceTableColumnTestIds } from '@/manager/modules/ui/data-table/data/data-table-column-test-ids';
import { verifyTaxCard } from '@/manager/modules/ui/tax/tax-assertions';
import { expectSingleLocatorToHaveText } from '@/manager/shared/utils/expect-utils';
import { BookingPlan } from '@/shared/types/booking-plan-types';
import { expect } from '@/shared/utils/matchers';

for (const tc of insuranceCreateHappyTestCases) {
  test(tc.description, async ({ insuranceCreateDialog, trackInsuranceForTeardown }) => {
    const data = getInsuranceCreateData(tc.options);
    const shortDescription = data.shortDescription?.[data.location.customerDefaultLanguage.id];

    await insuranceCreateDialog.goto();

    const detailsPage = await test.step('create insurance', () => insuranceCreateDialog.create(data));

    trackInsuranceForTeardown(detailsPage.getInsuranceId());

    await test.step('verify new insurance on details page', async () => {
      await expectSingleLocatorToHaveText(detailsPage.title, data.name);
      await expectSingleLocatorToHaveText(detailsPage.generalCard.name, data.name);
      await expectSingleLocatorToHaveText(detailsPage.generalCard.location, data.location.name);
      await expectSingleLocatorToHaveText(detailsPage.bookingPortalCard.shortDescription, shortDescription);
      await verifyTaxCard(detailsPage.taxCard, data.taxes);
      await verifyBookingPlansTable(
        detailsPage.bookingPlanCard.dataTable,
        data.bookingPlans,
        data.location.currency,
        'insurance'
      );
    });

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

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

      await expect(listPage.dataTable.getRows()).toHaveCount(1);
      await expect(listPage.dataTable.getRowColumn(0, insuranceTableColumnTestIds.id)).not.toBeEmpty();
      await expectDataTableTextColumnToHaveText(listPage.dataTable, insuranceTableColumnTestIds.name, data.name);
      await expectDataTableTextColumnToHaveText(
        listPage.dataTable,
        insuranceTableColumnTestIds.location,
        data.location.name
      );
    });
  });
}

test('rejects an insurance without all required fields', async ({ insuranceCreateDialog }) => {
  const data = getInsuranceCreateData({ bookingPlans: [] });

  await insuranceCreateDialog.goto();

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

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

test.fail('rejects an insurance with a duplicate name @bug', async ({ createInsurance, insuranceCreateDialog }) => {
  const existing = await createInsurance(getInsuranceCreateData());
  const data = getInsuranceCreateData({ name: existing.name });

  await insuranceCreateDialog.goto();

  await test.step('submit insurance create form with duplicate name', async () => {
    await insuranceCreateDialog.fill(data);
    await insuranceCreateDialog.submit();
  });

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

for (const tc of insuranceCreateUnhappyTestCases) {
  test(tc.description, async ({ insuranceCreateDialog }) => {
    const data = getInsuranceCreateData(tc.options);

    await insuranceCreateDialog.goto();

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

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

for (const tc of insuranceCreateBookingPlanUnhappyTestCases) {
  test(tc.description, async ({ insuranceCreateDialog }) => {
    await insuranceCreateDialog.goto();

    await test.step('verify invalid booking plans cannot be added', async () => {
      for (const plan of tc.bookingPlans) {
        const bookingPlanAddDialog = await insuranceCreateDialog.bookingPlanFieldSet.openBookingPlanAddDialog();
        await bookingPlanAddDialog.fill(plan);
        await bookingPlanAddDialog.submit();
        await expect(bookingPlanAddDialog.errors.or(bookingPlanAddDialog.notUniqueSnackbar)).toHaveCountGreaterThan(0);
        await bookingPlanAddDialog.cancel();
        await bookingPlanAddDialog.main.waitFor({ state: 'hidden' });
      }
    });

    await test.step('verify booking plans table is empty', async () => {
      await expect(insuranceCreateDialog.bookingPlanFieldSet.dataTable.getRows()).toHaveCount(0);
    });
  });
}

test('rejects an insurance with two booking plans sharing period and amount', async ({ insuranceCreateDialog }) => {
  const plan: BookingPlan = {
    period: 'weekly',
    amount: 1,
    priceExclVat: 50,
    discount: undefined,
    publish: true,
  };

  await insuranceCreateDialog.goto();

  await test.step('add two duplicate booking plans', () =>
    insuranceCreateDialog.bookingPlanFieldSet.fill([plan, plan]));

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