import {
  getDefaultProductRecurringCreateMixedBookingPlans,
  getProductRecurringCreateData,
} from '@/manager/modules/product/product-factories';
import { test } from '@/manager/modules/product/product-fixtures';
import { applyProductRecurringAddBookingPlans } from '@/manager/modules/product/product-mappers';
import { productRecurringAddBookingPlansHappyTestCases } from '@/manager/modules/product/test-cases/product-recurring-add-booking-plans-happy-test-cases';
import { verifyBookingPlansTable } from '@/manager/modules/ui/booking-plan/booking-plan-assertions';
import { BookingPlan } from '@/shared/types/booking-plan-types';
import { expect } from '@/shared/utils/matchers';

for (const tc of productRecurringAddBookingPlansHappyTestCases) {
  test(tc.description, async ({ createProductRecurring, productRecurringDetailsPage }) => {
    const product = await createProductRecurring(getProductRecurringCreateData(tc.initialOptions));
    const newProduct = applyProductRecurringAddBookingPlans(product, tc.changes);

    await productRecurringDetailsPage.goto(product.id);

    await test.step('add booking plans', () => productRecurringDetailsPage.bookingPlanCard.fill(tc.changes.plans));

    await test.step('verify booking plans on details page', () =>
      verifyBookingPlansTable(
        productRecurringDetailsPage.bookingPlanCard.dataTable,
        newProduct.bookingPlans,
        newProduct.location.currency,
        'recurringProduct'
      ));
  });
}

test('rejects adding a duplicate booking plan', async ({ createProductRecurring, productRecurringDetailsPage }) => {
  const duplicatePlans: { description: string; plan: BookingPlan }[] = [
    {
      description: 'a duplicate weekly period amount',
      plan: { period: 'weekly', amount: 8, priceExclVat: 77, discount: 50, publish: false },
    },
    {
      description: 'a duplicate monthly period amount',
      plan: { period: 'monthly', amount: 5, priceExclVat: 77, discount: 50, publish: false },
    },
  ];

  const product = await createProductRecurring(
    getProductRecurringCreateData({ bookingPlans: getDefaultProductRecurringCreateMixedBookingPlans() })
  );

  await productRecurringDetailsPage.goto(product.id);

  for (const { description, plan } of duplicatePlans) {
    await test.step(`verify ${description} is rejected`, async () => {
      const dialog = await productRecurringDetailsPage.bookingPlanCard.openBookingPlanAddDialog();
      await dialog.fill(plan);
      await dialog.submit();
      await expect(dialog.errors.or(dialog.notUniqueSnackbar)).toHaveCountGreaterThan(0);
      await dialog.cancel();
      await dialog.main.waitFor({ state: 'hidden' });
    });
  }
});

test('rejects adding a booking plan with an invalid input', async ({
  createProductRecurring,
  productRecurringDetailsPage,
}) => {
  const invalidPlans: { description: string; plan: BookingPlan }[] = [
    {
      description: 'a weekly period amount beyond the max',
      plan: { period: 'weekly', amount: 53, priceExclVat: 77, discount: 50, publish: false },
    },
    {
      description: 'a weekly period amount below the min',
      plan: { period: 'weekly', amount: 0, priceExclVat: 77, discount: 50, publish: false },
    },
    {
      description: 'a monthly period amount beyond the max',
      plan: { period: 'monthly', amount: 13, priceExclVat: 77, discount: 50, publish: false },
    },
    {
      description: 'a monthly period amount below the min',
      plan: { period: 'monthly', amount: 0, priceExclVat: 77, discount: 50, publish: false },
    },
  ];

  const product = await createProductRecurring(getProductRecurringCreateData());

  await productRecurringDetailsPage.goto(product.id);

  for (const { description, plan } of invalidPlans) {
    await test.step(`verify ${description} is rejected`, async () => {
      const dialog = await productRecurringDetailsPage.bookingPlanCard.openBookingPlanAddDialog();
      await dialog.fill(plan);
      await dialog.submit();
      await expect(dialog.errors).toHaveCountGreaterThan(0);
      await dialog.cancel();
      await dialog.main.waitFor({ state: 'hidden' });
    });
  }
});

test('rejects adding a booking plan without all required fields', async ({
  createProductRecurring,
  productRecurringDetailsPage,
}) => {
  const product = await createProductRecurring(getProductRecurringCreateData());

  await productRecurringDetailsPage.goto(product.id);

  const dialog = await test.step('submit empty form', async () => {
    const addDialog = await productRecurringDetailsPage.bookingPlanCard.openBookingPlanAddDialog();
    await addDialog.submit();
    return addDialog;
  });

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