import {
  createProductOneTimeViaApi,
  createProductRecurringViaApi,
  deleteProductOneTimeViaApi,
  deleteProductRecurringViaApi,
} from '@/manager/modules/product/product-api';
import { ProductOneTimeCreateData, ProductRecurringCreateData } from '@/manager/modules/product/product-types';
import { ProductListPage } from '@/manager/modules/product/views/ProductListPage';
import { ProductOneTimeCreateDialog } from '@/manager/modules/product/views/ProductOneTimeCreateDialog';
import { ProductOneTimeDetailsPage } from '@/manager/modules/product/views/ProductOneTimeDetailsPage';
import { ProductRecurringCreateDialog } from '@/manager/modules/product/views/ProductRecurringCreateDialog';
import { ProductRecurringDetailsPage } from '@/manager/modules/product/views/ProductRecurringDetailsPage';
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 { ProductOneTime, ProductRecurring } from '@/shared/types/product-types';
import { UnitType } from '@/shared/types/unit-type-types';

interface ProductFixtures {
  productListPage: ProductListPage;
  productOneTimeDetailsPage: ProductOneTimeDetailsPage;
  productRecurringDetailsPage: ProductRecurringDetailsPage;
  productOneTimeCreateDialog: ProductOneTimeCreateDialog;
  productRecurringCreateDialog: ProductRecurringCreateDialog;
  createProductOneTime: (data: ProductOneTimeCreateData) => Promise<ProductOneTime>;
  createProductRecurring: (data: ProductRecurringCreateData) => Promise<ProductRecurring>;
  createUnitType: (data: UnitTypeCreateData) => Promise<UnitType>;
  trackProductOneTimeForTeardown: (id: number) => void;
  trackProductRecurringForTeardown: (id: number) => void;
}

interface ProductInternalFixtures {
  productTeardown: { oneTimeIds: number[]; recurringIds: number[]; unitTypeIds: number[] };
}

export const test = apiTest.extend<ProductFixtures & ProductInternalFixtures>({
  productListPage: async ({ page }, use) => {
    await use(new ProductListPage(page));
  },

  productOneTimeDetailsPage: async ({ page }, use) => {
    await use(new ProductOneTimeDetailsPage(page));
  },

  productRecurringDetailsPage: async ({ page }, use) => {
    await use(new ProductRecurringDetailsPage(page));
  },

  productOneTimeCreateDialog: async ({ page }, use) => {
    await use(new ProductOneTimeCreateDialog(page));
  },

  productRecurringCreateDialog: async ({ page }, use) => {
    await use(new ProductRecurringCreateDialog(page));
  },

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

  createProductRecurring: async ({ managerApiRequest, productTeardown }, use) => {
    await use(async (data) => {
      const product = await apiTest.step('setup: create recurring product via API', () =>
        createProductRecurringViaApi(managerApiRequest, data)
      );
      productTeardown.recurringIds.push(product.id);
      return product;
    });
  },

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

  trackProductOneTimeForTeardown: async ({ productTeardown }, use) => {
    await use((id) => productTeardown.oneTimeIds.push(id));
  },

  trackProductRecurringForTeardown: async ({ productTeardown }, use) => {
    await use((id) => productTeardown.recurringIds.push(id));
  },

  productTeardown: async ({ managerApiRequest }, use) => {
    const oneTimeIds: number[] = [];
    const recurringIds: number[] = [];
    const unitTypeIds: number[] = [];

    await use({ oneTimeIds, recurringIds, 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 one-time products via API', () =>
      Promise.all(oneTimeIds.map((id) => deleteProductOneTimeViaApi(managerApiRequest, id)))
    );
    await apiTest.step('teardown: delete created recurring products via API', () =>
      Promise.all(recurringIds.map((id) => deleteProductRecurringViaApi(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';
