import { IBookingCreateData } from '@/manager/modules/booking/types/booking-types';
import { toBookingItemsDetails, toTotalsSummary } from '@/manager/modules/booking/utils/booking-create-transform-utils';
import { expectBookingDetailsItemsSectionToShowCorrectData } from '@/manager/modules/booking/utils/booking-entity-expect-utils';
import { BookingListPage } from '@/manager/modules/booking/views/BookingListPage';
import { bookingTableColumnTestIds } from '@/manager/modules/ui/data-table/data/data-table-column-test-ids';
import {
  expectDataTableTextColumnToHaveText,
  expectDataTableChipsColumnToHaveText,
} from '@/manager/modules/ui/data-table/utils/data-table-expect-utils';
import { expectTotalsSummarySectionToDisplayCorrectData } from '@/manager/modules/ui/totals-summary/utils/totals-summary-expect-utils';
import { expectSingleLocatorToHaveText } from '@/manager/shared/utils/expect-utils';
import { getFutureDate } from '@/shared/utils/date-utils';
import {
  formatDate,
  formatBillingPeriod,
  formatCurrency,
  formatDateRange,
  formatPaymentMethod,
} from '@/shared/utils/format-utils';
import { expect } from '@/shared/utils/matcher-utils';

export async function expectBookingToBeCreated(startPage: BookingListPage, data: IBookingCreateData): Promise<void> {
  const totalsSummary = toTotalsSummary(data);

  const createDialog = await startPage.openBookingCreateDialog();
  await createDialog.fill(data);

  await expectTotalsSummarySectionToDisplayCorrectData(
    createDialog.productsFieldSet.totalsSummarySection,
    totalsSummary,
    data.location.currency
  );

  const detailsPage = await createDialog.submit();

  await expect(detailsPage.title).not.toBeEmpty();

  const bookingId = (await detailsPage.title.innerText()).trim().split(' ')[1];
  const bookingCreatedAt = formatDate(new Date());
  const bookingMoveInDate = formatDate(data.moveInDate);
  const bookingIsFutureMoveInDate = bookingCreatedAt !== bookingMoveInDate;
  const bookingStatus = !bookingIsFutureMoveInDate ? 'active' : 'scheduled';
  const bookingIsMonthlyPeriod = data.unitType.billing.type === 'monthly';
  const bookingPlan = formatBillingPeriod(
    data.unitType.billing.type,
    data.unitType.billing.plan.amount,
    data.unitType.billing.plan.name
  );
  const bookingCurrentPeriodEndDate =
    bookingStatus === 'active'
      ? getFutureDate(data.unitType.billing.plan.amount, bookingIsMonthlyPeriod ? 'month' : 'week')
      : undefined;
  const bookingCurrentPeriod = bookingCurrentPeriodEndDate
    ? formatDateRange(data.moveInDate, bookingCurrentPeriodEndDate)
    : undefined;
  const bookingNextInvoiceDate = formatDate(bookingCurrentPeriodEndDate ?? data.moveInDate);
  const bookingPaymentMethod =
    data.payment.option === 'charge_automatically' && data.payment.method
      ? formatPaymentMethod(data.payment.method, true)
      : undefined;
  const bookingItemsDetails = toBookingItemsDetails(data);

  await expectSingleLocatorToHaveText(detailsPage.title, `booking ${bookingId}`);
  await expectSingleLocatorToHaveText(detailsPage.baseStatus, bookingStatus);
  await expectSingleLocatorToHaveText(detailsPage.generalCard.customer, data.customer.name);
  await expectSingleLocatorToHaveText(detailsPage.generalCard.location, data.location.name);
  await expectSingleLocatorToHaveText(detailsPage.generalCard.createdAt, bookingCreatedAt);
  await expectSingleLocatorToHaveText(detailsPage.generalCard.moveIn, bookingMoveInDate);
  await expectSingleLocatorToHaveText(detailsPage.generalCard.moveOut, undefined);
  await expectSingleLocatorToHaveText(detailsPage.generalCard.discount, data.discount?.name);
  await expectSingleLocatorToHaveText(detailsPage.notesCard.note, data.note);
  await expectSingleLocatorToHaveText(detailsPage.billingCard.bookingPlan, bookingPlan);
  await expectSingleLocatorToHaveText(detailsPage.billingCard.currentPeriod, bookingCurrentPeriod);
  await expectSingleLocatorToHaveText(
    detailsPage.billingCard.amountExclVat,
    formatCurrency(bookingItemsDetails.totalExclVat, data.location.currency)
  );
  await expectSingleLocatorToHaveText(detailsPage.billingCard.priceAdjustment, undefined);
  await expectSingleLocatorToHaveText(detailsPage.billingCard.nextInvoice, bookingNextInvoiceDate);
  bookingPaymentMethod
    ? await expectSingleLocatorToHaveText(detailsPage.billingCard.paymentMethod, bookingPaymentMethod)
    : await expect(detailsPage.billingCard.paymentMethod).toHaveCount(0);
  await expectSingleLocatorToHaveText(
    detailsPage.billingCard.paymentOption,
    data.payment.option === 'pay_manually' ? 'Manual payment' : 'Automatic payment through Stripe'
  );
  await expectBookingDetailsItemsSectionToShowCorrectData(
    detailsPage.itemsCard.itemsSection,
    bookingItemsDetails,
    data.location.currency
  );
  // TODO: further checks for invoice and payment table skipped until stripe webhook issues are fixed
  // await expect(await detailView.invoicesDataTable.getRows()).toHaveCount(!bookingFutureMoveInDate ? 1 : 0);
  // await expect(await detailView.paymentsDataTable.getRows()).toHaveCount(!bookingFutureMoveInDate ? 1 : 0);

  const listPage = await detailsPage.returnToBookingListPage();
  await listPage.filter({
    search: bookingId,
  });

  await expect(listPage.dataTable.getRows()).toHaveCount(1);
  await expectDataTableTextColumnToHaveText(listPage.dataTable, bookingTableColumnTestIds.id, bookingId);
  await expectDataTableTextColumnToHaveText(listPage.dataTable, bookingTableColumnTestIds.location, data.location.name);
  await expectDataTableChipsColumnToHaveText(listPage.dataTable, bookingTableColumnTestIds.status, bookingStatus);
  await expectDataTableTextColumnToHaveText(listPage.dataTable, bookingTableColumnTestIds.customer, data.customer.name);
  await expectDataTableTextColumnToHaveText(listPage.dataTable, bookingTableColumnTestIds.unit, data.unit);
  await expectDataTableTextColumnToHaveText(listPage.dataTable, bookingTableColumnTestIds.billingPeriod, bookingPlan);
  await expectDataTableTextColumnToHaveText(
    listPage.dataTable,
    bookingTableColumnTestIds.nextInvoice,
    bookingNextInvoiceDate
  );
  await expectDataTableTextColumnToHaveText(listPage.dataTable, bookingTableColumnTestIds.createdAt, bookingCreatedAt);
  await expectDataTableTextColumnToHaveText(listPage.dataTable, bookingTableColumnTestIds.moveIn, bookingMoveInDate);
  await expectDataTableTextColumnToHaveText(listPage.dataTable, bookingTableColumnTestIds.moveOut, undefined);
}

export async function expectBookingToNotBeCreated(page: BookingListPage, data: IBookingCreateData): Promise<void> {
  const createDialog = await page.openBookingCreateDialog();
  await createDialog.fill(data);

  if (await createDialog.submitButton.isEnabled()) await createDialog.submitButton.click();

  await expect(createDialog.errors).toHaveCountGreaterThan(0);
}
