import { type EmptyFields, type FieldsToInsertable } from "@tailor-platform/erp-kit/core";
import { type TailorAnyDBField } from "@tailor-platform/sdk";
import type { defineModule as defineItemManagementModule } from "../item-management";
import type { defineModule as defineOrganizationModule } from "../organization";
import { activateBillOfMaterial } from "./command/activateBillOfMaterial.generated";
import { activateRouting } from "./command/activateRouting.generated";
import { activateWorkCenter } from "./command/activateWorkCenter.generated";
import { cancelProductionOrder } from "./command/cancelProductionOrder.generated";
import { closeProductionOrder } from "./command/closeProductionOrder.generated";
import { completeProductionOrder } from "./command/completeProductionOrder.generated";
import { completeWorkOrder } from "./command/completeWorkOrder.generated";
import { createBillOfMaterial } from "./command/createBillOfMaterial.generated";
import { createProductionOrder } from "./command/createProductionOrder.generated";
import { createRouting } from "./command/createRouting.generated";
// Commands
import { createWorkCenter } from "./command/createWorkCenter.generated";
import { deactivateBillOfMaterial } from "./command/deactivateBillOfMaterial.generated";
import { deactivateRouting } from "./command/deactivateRouting.generated";
import { deactivateWorkCenter } from "./command/deactivateWorkCenter.generated";
import { pauseWorkOrder } from "./command/pauseWorkOrder.generated";
import { recordInventoryIssueOutcome } from "./command/recordInventoryIssueOutcome.generated";
import { recordManufacturingCostSettlementAcknowledgment } from "./command/recordManufacturingCostSettlementAcknowledgment.generated";
import { releaseProductionOrder } from "./command/releaseProductionOrder.generated";
import { reopenProductionOrder } from "./command/reopenProductionOrder.generated";
import { reportWorkOrderProgress } from "./command/reportWorkOrderProgress.generated";
import { rescheduleProductionOrder } from "./command/rescheduleProductionOrder.generated";
import { resumeWorkOrder } from "./command/resumeWorkOrder.generated";
import { reviewManufacturingCostSummary } from "./command/reviewManufacturingCostSummary.generated";
import { startWorkOrder } from "./command/startWorkOrder.generated";
import { technicallyCompleteProductionOrder } from "./command/technicallyCompleteProductionOrder.generated";
import { unreleaseProductionOrder } from "./command/unreleaseProductionOrder.generated";
import { updateBillOfMaterial } from "./command/updateBillOfMaterial.generated";
import { updateProductionOrder } from "./command/updateProductionOrder.generated";
import { updateRouting } from "./command/updateRouting.generated";
import { updateWorkCenter } from "./command/updateWorkCenter.generated";
import { createBillOfMaterialType, type CreateBillOfMaterialTypeParams } from "./db/billOfMaterial";
import { createBillOfMaterialLineType } from "./db/billOfMaterialLine";
import { createCostVarianceLineType } from "./db/costVarianceLine";
import { createManufacturingCostLineType } from "./db/manufacturingCostLine";
import { createManufacturingCostSettlementRecordType } from "./db/manufacturingCostSettlementRecord";
import { createManufacturingCostSummaryType } from "./db/manufacturingCostSummary";
import {
  createProductionOrderType,
  type CreateProductionOrderTypeParams,
} from "./db/productionOrder";
import { createProductionOrderBomSnapshotType } from "./db/productionOrderBomSnapshot";
import { createProductionOrderCostBaselineType } from "./db/productionOrderCostBaseline";
import { createProductionOrderMaterialRequirementType } from "./db/productionOrderMaterialRequirement";
import { createProductionOrderRoutingSnapshotType } from "./db/productionOrderRoutingSnapshot";
import { createRoutingType, type CreateRoutingTypeParams } from "./db/routing";
import { createRoutingOperationType } from "./db/routingOperation";
import { createWorkCenterType, type CreateWorkCenterTypeParams } from "./db/workCenter";
import { createWorkOrderType } from "./db/workOrder";
import { createWorkOrderExecutionEventType } from "./db/workOrderExecutionEvent";
import { detectBillOfMaterialCircularReference } from "./query/detectBillOfMaterialCircularReference.generated";
import { explodeBillOfMaterial } from "./query/explodeBillOfMaterial.generated";
import { getBillOfMaterial } from "./query/getBillOfMaterial.generated";
import { getManufacturingCostSummary } from "./query/getManufacturingCostSummary.generated";
import { getProductionOrder } from "./query/getProductionOrder.generated";
import { getRouting } from "./query/getRouting.generated";
// Queries
import { getWorkCenter } from "./query/getWorkCenter.generated";
import { getWorkOrder } from "./query/getWorkOrder.generated";
import { listBillOfMaterialsByItem } from "./query/listBillOfMaterialsByItem.generated";
import { listManufacturingCostSummariesByStatus } from "./query/listManufacturingCostSummariesByStatus.generated";
import { listProductionOrdersByStatus } from "./query/listProductionOrdersByStatus.generated";
import { listRoutingsByItem } from "./query/listRoutingsByItem.generated";
import { listWorkCentersBySite } from "./query/listWorkCentersBySite.generated";
import { listWorkOrdersByProductionOrder } from "./query/listWorkOrdersByProductionOrder.generated";
import { listWorkOrdersByWorkCenter } from "./query/listWorkOrdersByWorkCenter.generated";

type OrganizationModule = ReturnType<typeof defineOrganizationModule>;
type OrganizationDB = OrganizationModule["db"];
export type OrganizationQueries = OrganizationModule["queries"];

type ItemManagementModule = ReturnType<typeof defineItemManagementModule>;
type ItemManagementDB = ItemManagementModule["db"];
export type ItemManagementQueries = ItemManagementModule["queries"];

export interface DefineModuleParams<
  WCF extends Record<string, TailorAnyDBField>,
  RTF extends Record<string, TailorAnyDBField>,
  BMF extends Record<string, TailorAnyDBField>,
  POF extends Record<string, TailorAnyDBField>,
> {
  workCenter?: Omit<CreateWorkCenterTypeParams<WCF>, "companyType" | "siteType">;
  routing?: Omit<CreateRoutingTypeParams<RTF>, "companyType" | "siteType" | "itemType">;
  billOfMaterial?: Omit<
    CreateBillOfMaterialTypeParams<BMF>,
    "companyType" | "siteType" | "itemType"
  >;
  productionOrder?: Omit<
    CreateProductionOrderTypeParams<POF>,
    "companyType" | "siteType" | "itemType"
  >;
  organization: {
    db: { company: OrganizationDB["company"]; site: OrganizationDB["site"] };
    queries: Pick<OrganizationQueries, "getSite">;
  };
  itemManagement: {
    db: { item: ItemManagementDB["item"] };
    queries: Pick<ItemManagementQueries, "getItem">;
  };
}

/* @__NO_SIDE_EFFECTS__ */
export const defineModule = <
  const WCF extends Record<string, TailorAnyDBField> = EmptyFields,
  const RTF extends Record<string, TailorAnyDBField> = EmptyFields,
  const BMF extends Record<string, TailorAnyDBField> = EmptyFields,
  const POF extends Record<string, TailorAnyDBField> = EmptyFields,
>(
  params: DefineModuleParams<WCF, RTF, BMF, POF>,
) => {
  const companyType = params.organization.db.company;
  const siteType = params.organization.db.site;
  const itemType = params.itemManagement.db.item;

  // Master data
  const workCenter = createWorkCenterType({
    ...params.workCenter,
    companyType,
    siteType,
  });
  const routing = createRoutingType({ ...params.routing, companyType, siteType, itemType });
  const routingOperation = createRoutingOperationType();
  const billOfMaterial = createBillOfMaterialType({
    ...params.billOfMaterial,
    companyType,
    siteType,
    itemType,
  });
  const billOfMaterialLine = createBillOfMaterialLineType({
    itemType,
  });

  // Production orders
  const productionOrder = createProductionOrderType({
    ...params.productionOrder,
    companyType,
    siteType,
    itemType,
  });
  const productionOrderMaterialRequirement = createProductionOrderMaterialRequirementType({
    itemType,
  });
  const productionOrderBomSnapshot = createProductionOrderBomSnapshotType({});
  const productionOrderRoutingSnapshot = createProductionOrderRoutingSnapshotType({});
  const productionOrderCostBaseline = createProductionOrderCostBaselineType({});

  // Work orders
  const workOrder = createWorkOrderType();
  const workOrderExecutionEvent = createWorkOrderExecutionEventType();

  // Cost management
  const manufacturingCostSummary = createManufacturingCostSummaryType();
  const manufacturingCostLine = createManufacturingCostLineType();
  const costVarianceLine = createCostVarianceLineType();
  const manufacturingCostSettlementRecord = createManufacturingCostSettlementRecordType();

  return {
    db: {
      workCenter,
      routing,
      routingOperation,
      billOfMaterial,
      billOfMaterialLine,
      productionOrder,
      productionOrderMaterialRequirement,
      productionOrderBomSnapshot,
      productionOrderRoutingSnapshot,
      productionOrderCostBaseline,
      workOrder,
      workOrderExecutionEvent,
      manufacturingCostSummary,
      manufacturingCostLine,
      costVarianceLine,
      manufacturingCostSettlementRecord,
    },
    queries: {
      getWorkCenter,
      listWorkCentersBySite,
      getRouting,
      listRoutingsByItem,
      getBillOfMaterial,
      listBillOfMaterialsByItem,
      detectBillOfMaterialCircularReference,
      explodeBillOfMaterial,
      getProductionOrder,
      listProductionOrdersByStatus,
      getWorkOrder,
      listWorkOrdersByProductionOrder,
      listWorkOrdersByWorkCenter,
      getManufacturingCostSummary,
      listManufacturingCostSummariesByStatus,
    },
    commands: {
      createWorkCenter: createWorkCenter<FieldsToInsertable<WCF>>(),
      updateWorkCenter: updateWorkCenter<FieldsToInsertable<WCF>>(),
      activateWorkCenter: activateWorkCenter(),
      deactivateWorkCenter: deactivateWorkCenter(),
      createRouting: createRouting<FieldsToInsertable<RTF>>(params.itemManagement.queries),
      updateRouting: updateRouting<FieldsToInsertable<RTF>>(),
      activateRouting: activateRouting(),
      deactivateRouting: deactivateRouting(),
      createBillOfMaterial: createBillOfMaterial<FieldsToInsertable<BMF>>(
        params.itemManagement.queries,
      ),
      updateBillOfMaterial: updateBillOfMaterial<FieldsToInsertable<BMF>>(
        params.itemManagement.queries,
      ),
      activateBillOfMaterial: activateBillOfMaterial(params.itemManagement.queries),
      deactivateBillOfMaterial: deactivateBillOfMaterial(),
      createProductionOrder: createProductionOrder<FieldsToInsertable<POF>>(
        params.itemManagement.queries,
        params.organization.queries,
      ),
      updateProductionOrder: updateProductionOrder<FieldsToInsertable<POF>>(),
      releaseProductionOrder: releaseProductionOrder(params.itemManagement.queries),
      unreleaseProductionOrder: unreleaseProductionOrder(),
      rescheduleProductionOrder: rescheduleProductionOrder(),
      cancelProductionOrder: cancelProductionOrder(),
      reopenProductionOrder: reopenProductionOrder(),
      completeProductionOrder: completeProductionOrder(),
      technicallyCompleteProductionOrder: technicallyCompleteProductionOrder(),
      closeProductionOrder: closeProductionOrder(),
      startWorkOrder: startWorkOrder(),
      pauseWorkOrder: pauseWorkOrder(),
      resumeWorkOrder: resumeWorkOrder(),
      completeWorkOrder: completeWorkOrder(),
      reportWorkOrderProgress: reportWorkOrderProgress(),
      recordInventoryIssueOutcome: recordInventoryIssueOutcome(),
      reviewManufacturingCostSummary: reviewManufacturingCostSummary(),
      recordManufacturingCostSettlementAcknowledgment:
        recordManufacturingCostSettlementAcknowledgment(),
    },
  };
};
