import { createDepositViaApi, deleteDepositViaApi } from '@/manager/modules/deposit/deposit-api';
import { DepositCreateData } from '@/manager/modules/deposit/deposit-types';
import { createDiscountViaApi, deleteDiscountViaApi } from '@/manager/modules/discount/discount-api';
import { DiscountCreateData } from '@/manager/modules/discount/discount-types';
import { DiscountCreateDialog } from '@/manager/modules/discount/views/DiscountCreateDialog';
import { DiscountDetailsPage } from '@/manager/modules/discount/views/DiscountDetailsPage';
import { DiscountListPage } from '@/manager/modules/discount/views/DiscountListPage';
import { createProductOneTimeViaApi, deleteProductOneTimeViaApi } from '@/manager/modules/product/product-api';
import { ProductOneTimeCreateData } from '@/manager/modules/product/product-types';
import { createUnitTypeViaApi, deleteUnitTypeViaApi } from '@/manager/modules/unit-type/unit-type-api';
import { UnitTypeCreateData } from '@/manager/modules/unit-type/unit-type-types';
import { test as apiTest } from '@/manager/shared/api-fixtures';
import { Deposit } from '@/shared/types/deposit-types';
import { Discount } from '@/shared/types/discount-types';
import { ProductOneTime } from '@/shared/types/product-types';
import { UnitType } from '@/shared/types/unit-type-types';

interface DiscountFixtures {
  discountListPage: DiscountListPage;
  discountDetailsPage: DiscountDetailsPage;
  discountCreateDialog: DiscountCreateDialog;
  createDiscount: (data: DiscountCreateData) => Promise<Discount>;
  createProductOneTime: (data: ProductOneTimeCreateData) => Promise<ProductOneTime>;
  createDeposit: (data: DepositCreateData) => Promise<Deposit>;
  createUnitType: (data: UnitTypeCreateData) => Promise<UnitType>;
  trackDiscountForTeardown: (id: number) => void;
}

interface DiscountInternalFixtures {
  discountTeardown: {
    discountIds: number[];
    productOneTimeIds: number[];
    depositIds: number[];
    unitTypeIds: number[];
  };
}

export const test = apiTest.extend<DiscountFixtures & DiscountInternalFixtures>({
  discountListPage: async ({ page }, use) => {
    await use(new DiscountListPage(page));
  },

  discountDetailsPage: async ({ page }, use) => {
    await use(new DiscountDetailsPage(page));
  },

  discountCreateDialog: async ({ page }, use) => {
    await use(new DiscountCreateDialog(page));
  },

  createDiscount: async ({ managerApiRequest, discountTeardown }, use) => {
    await use(async (data) => {
      const discount = await apiTest.step('setup: create discount via API', () =>
        createDiscountViaApi(managerApiRequest, data)
      );
      discountTeardown.discountIds.push(discount.id);
      return discount;
    });
  },

  createProductOneTime: async ({ managerApiRequest, discountTeardown }, use) => {
    await use(async (data) => {
      const product = await apiTest.step('setup: create one-time product via API', () =>
        createProductOneTimeViaApi(managerApiRequest, data)
      );
      discountTeardown.productOneTimeIds.push(product.id);
      return product;
    });
  },

  createDeposit: async ({ managerApiRequest, discountTeardown }, use) => {
    await use(async (data) => {
      const deposit = await apiTest.step('setup: create deposit via API', () =>
        createDepositViaApi(managerApiRequest, data)
      );
      discountTeardown.depositIds.push(deposit.id);
      return deposit;
    });
  },

  createUnitType: async ({ managerApiRequest, discountTeardown }, use) => {
    await use(async (data) => {
      const unitType = await apiTest.step('setup: create unit type via API', () =>
        createUnitTypeViaApi(managerApiRequest, data)
      );
      discountTeardown.unitTypeIds.push(unitType.id);
      return unitType;
    });
  },

  trackDiscountForTeardown: async ({ discountTeardown }, use) => {
    await use((id) => discountTeardown.discountIds.push(id));
  },

  discountTeardown: async ({ managerApiRequest }, use) => {
    const discountIds: number[] = [];
    const productOneTimeIds: number[] = [];
    const depositIds: number[] = [];
    const unitTypeIds: number[] = [];

    await use({ discountIds, productOneTimeIds, depositIds, unitTypeIds });

    // TODO(KIN-4692): Teardown is disabled for now. Deleting these entities kicks off a flood of async
    // backend jobs, and when the job queue backs up, the jobs other e2e tests rely on (e.g. invoice
    // generation) don't run in time and those tests fail. Until the queue pressure is sorted out, we
    // leave all created entities for the env reseed to clean up rather than tearing down here.
    return;

    await apiTest.step('teardown: delete created discounts via API', () =>
      Promise.all(discountIds.map((id) => deleteDiscountViaApi(managerApiRequest, id)))
    );
    await apiTest.step('teardown: delete created one-time products via API', () =>
      Promise.all(productOneTimeIds.map((id) => deleteProductOneTimeViaApi(managerApiRequest, id)))
    );
    await apiTest.step('teardown: delete created deposits via API', () =>
      Promise.all(depositIds.map((id) => deleteDepositViaApi(managerApiRequest, id)))
    );
    await apiTest.step('teardown: delete created unit types via API', () =>
      Promise.all(unitTypeIds.map((id) => deleteUnitTypeViaApi(managerApiRequest, id)))
    );
  },
});

export { expect } from '@playwright/test';
