import type { TailorAnyDBField } from "@tailor-platform/sdk";
import type { defineModule as defineBusinessPartnerModule } from "../business-partner";
import type { defineModule as defineInventoryModule } from "../inventory";
import type { defineModule as defineItemManagementModule } from "../item-management";
import type { defineModule as defineOrganizationModule } from "../organization";
import type { defineModule as definePrimitivesModule } from "../primitives";
import type { defineModule as defineUserManagementModule } from "../user-management";
import { activatePurchasePaymentTerm } from "./command/activatePurchasePaymentTerm.generated";
import { activatePurchasePriceList } from "./command/activatePurchasePriceList.generated";
import { activatePurchasePriceRule } from "./command/activatePurchasePriceRule.generated";
import { applyPurchaseChangeOrder } from "./command/applyPurchaseChangeOrder.generated";
import { approvePurchaseChangeOrder } from "./command/approvePurchaseChangeOrder.generated";
import { approvePurchaseOrder } from "./command/approvePurchaseOrder.generated";
import { approvePurchaseRequisition } from "./command/approvePurchaseRequisition.generated";
import { cancelGoodsReceipt } from "./command/cancelGoodsReceipt.generated";
import { cancelPurchaseBill } from "./command/cancelPurchaseBill.generated";
import { cancelPurchaseChangeOrder } from "./command/cancelPurchaseChangeOrder.generated";
import { cancelPurchaseOrder } from "./command/cancelPurchaseOrder.generated";
import { cancelPurchaseRequisition } from "./command/cancelPurchaseRequisition.generated";
import { closePurchaseOrder } from "./command/closePurchaseOrder.generated";
import { closePurchaseRequisition } from "./command/closePurchaseRequisition.generated";
import { convertPurchaseRequisitionToPurchaseOrder } from "./command/convertPurchaseRequisitionToPurchaseOrder.generated";
import { createGoodsReceipt } from "./command/createGoodsReceipt.generated";
import { createPurchaseBill } from "./command/createPurchaseBill.generated";
import { createPurchaseChangeOrder } from "./command/createPurchaseChangeOrder.generated";
import { createPurchaseOrder } from "./command/createPurchaseOrder.generated";
import { createPurchasePaymentTerm } from "./command/createPurchasePaymentTerm.generated";
import { createPurchaseRequisition } from "./command/createPurchaseRequisition.generated";
import { createPurchasePriceList } from "./command/createPurchasePriceList.generated";
import { createPurchasePriceRule } from "./command/createPurchasePriceRule.generated";
import { deactivatePurchasePaymentTerm } from "./command/deactivatePurchasePaymentTerm.generated";
import { deactivatePurchasePriceList } from "./command/deactivatePurchasePriceList.generated";
import { deactivatePurchasePriceRule } from "./command/deactivatePurchasePriceRule.generated";
import { matchPurchaseBill } from "./command/matchPurchaseBill.generated";
import { postGoodsReceipt } from "./command/postGoodsReceipt.generated";
import { recallPurchaseRequisition } from "./command/recallPurchaseRequisition.generated";
import { rejectPurchaseChangeOrder } from "./command/rejectPurchaseChangeOrder.generated";
import { rejectPurchaseOrder } from "./command/rejectPurchaseOrder.generated";
import { rejectPurchaseRequisition } from "./command/rejectPurchaseRequisition.generated";
import { releasePurchaseBill } from "./command/releasePurchaseBill.generated";
import { setSupplierDefaultPurchasePaymentTerm } from "./command/setSupplierDefaultPurchasePaymentTerm.generated";
import { submitPurchaseChangeOrder } from "./command/submitPurchaseChangeOrder.generated";
import { submitPurchaseOrder } from "./command/submitPurchaseOrder.generated";
import { submitPurchaseRequisition } from "./command/submitPurchaseRequisition.generated";
import { updateGoodsReceipt } from "./command/updateGoodsReceipt.generated";
import { updatePurchaseBill } from "./command/updatePurchaseBill.generated";
import { updatePurchaseOrder } from "./command/updatePurchaseOrder.generated";
import { updatePurchasePaymentTerm } from "./command/updatePurchasePaymentTerm.generated";
import { updatePurchasePriceList } from "./command/updatePurchasePriceList.generated";
import { updatePurchaseRequisition } from "./command/updatePurchaseRequisition.generated";
import { updatePurchaseChangeOrder } from "./command/updatePurchaseChangeOrder.generated";
import { updatePurchasePriceRule } from "./command/updatePurchasePriceRule.generated";
import {
  createPurchaseChangeOrderType,
  type CreatePurchaseChangeOrderTypeParams,
} from "./db/purchaseChangeOrder";
import {
  createPurchaseChangeOrderLineType,
  type CreatePurchaseChangeOrderLineTypeParams,
} from "./db/purchaseChangeOrderLine";
import {
  createGoodsReceiptLineType,
  type CreateGoodsReceiptLineTypeParams,
} from "./db/goodsReceiptLine";
import { createGoodsReceiptType, type CreateGoodsReceiptTypeParams } from "./db/goodsReceipt";
import {
  createPurchaseBillLineType,
  type CreatePurchaseBillLineTypeParams,
} from "./db/purchaseBillLine";
import { createPurchaseBillType, type CreatePurchaseBillTypeParams } from "./db/purchaseBill";
import {
  createPurchaseOrderLineType,
  type CreatePurchaseOrderLineTypeParams,
} from "./db/purchaseOrderLine";
import { createPurchaseOrderType, type CreatePurchaseOrderTypeParams } from "./db/purchaseOrder";
import {
  createPurchasePaymentTermType,
  type CreatePurchasePaymentTermTypeParams,
} from "./db/purchasePaymentTerm";
import { createPurchasePaymentTermLineType } from "./db/purchasePaymentTermLine";
import {
  createPurchasePriceListType,
  type CreatePurchasePriceListTypeParams,
} from "./db/purchasePriceList";
import {
  createPurchasePriceRuleType,
  type CreatePurchasePriceRuleTypeParams,
} from "./db/purchasePriceRule";
import {
  createPurchaseRequisitionType,
  type CreatePurchaseRequisitionTypeParams,
} from "./db/purchaseRequisition";
import {
  createPurchaseRequisitionLineType,
  type CreatePurchaseRequisitionLineTypeParams,
} from "./db/purchaseRequisitionLine";
import { createPurchaseRequisitionLineAllocationType } from "./db/purchaseRequisitionLineAllocation";
import { createThreeWayMatchEventType } from "./db/threeWayMatchEvent";
import {
  createSupplierProfileType,
  type CreateSupplierProfileTypeParams,
} from "./db/supplierProfile";
import { getPurchaseChangeOrder } from "./query/getPurchaseChangeOrder.generated";
import { calculatePurchaseBillDueSchedule } from "./query/calculatePurchaseBillDueSchedule.generated";
import { calculatePurchasePrice } from "./query/calculatePurchasePrice.generated";
import { getGoodsReceipt } from "./query/getGoodsReceipt.generated";
import { getPurchaseBill } from "./query/getPurchaseBill.generated";
import { getPurchaseOrder } from "./query/getPurchaseOrder.generated";
import { getPurchasePaymentTerm } from "./query/getPurchasePaymentTerm.generated";
import { getPurchasePriceList } from "./query/getPurchasePriceList.generated";
import { getPurchaseRequisition } from "./query/getPurchaseRequisition.generated";
import { getSupplierProfile } from "./query/getSupplierProfile.generated";

type OrganizationModule = ReturnType<typeof defineOrganizationModule>;
type OrganizationDB = OrganizationModule["db"];
type BusinessPartnerModule = ReturnType<typeof defineBusinessPartnerModule>;
type BusinessPartnerDB = BusinessPartnerModule["db"];
type InventoryModule = ReturnType<typeof defineInventoryModule>;
type InventoryCommands = InventoryModule["commands"];
type ItemManagementModule = ReturnType<typeof defineItemManagementModule>;
type ItemManagementDB = ItemManagementModule["db"];
type PrimitivesModule = ReturnType<typeof definePrimitivesModule>;
type PrimitivesDB = PrimitivesModule["db"];
type UserManagementModule = ReturnType<typeof defineUserManagementModule>;
type UserManagementDB = UserManagementModule["db"];
type BusinessPartnerQueries = BusinessPartnerModule["queries"];
type ItemManagementQueries = ItemManagementModule["queries"];
type PrimitivesQueries = PrimitivesModule["queries"];

export interface DefineModuleParams<
  SPF extends Record<string, TailorAnyDBField>,
  PTF extends Record<string, TailorAnyDBField>,
  PLF extends Record<string, TailorAnyDBField>,
  PRF extends Record<string, TailorAnyDBField>,
  POF extends Record<string, TailorAnyDBField>,
  POLF extends Record<string, TailorAnyDBField>,
  GRF extends Record<string, TailorAnyDBField>,
  GRLF extends Record<string, TailorAnyDBField>,
  PBF extends Record<string, TailorAnyDBField>,
  PBLF extends Record<string, TailorAnyDBField>,
  PRQF extends Record<string, TailorAnyDBField>,
  PRQLF extends Record<string, TailorAnyDBField>,
  PCOF extends Record<string, TailorAnyDBField>,
  PCOLF extends Record<string, TailorAnyDBField>,
> {
  supplierProfile?: CreateSupplierProfileTypeParams<SPF>;
  purchasePaymentTerm?: CreatePurchasePaymentTermTypeParams<PTF>;
  purchasePriceList?: CreatePurchasePriceListTypeParams<PLF>;
  purchasePriceRule?: CreatePurchasePriceRuleTypeParams<PRF>;
  purchaseOrder?: CreatePurchaseOrderTypeParams<POF>;
  purchaseOrderLine?: CreatePurchaseOrderLineTypeParams<POLF>;
  goodsReceipt?: CreateGoodsReceiptTypeParams<GRF>;
  goodsReceiptLine?: CreateGoodsReceiptLineTypeParams<GRLF>;
  purchaseBill?: CreatePurchaseBillTypeParams<PBF>;
  purchaseBillLine?: CreatePurchaseBillLineTypeParams<PBLF>;
  purchaseRequisition?: CreatePurchaseRequisitionTypeParams<PRQF>;
  purchaseRequisitionLine?: CreatePurchaseRequisitionLineTypeParams<PRQLF>;
  purchaseChangeOrder?: CreatePurchaseChangeOrderTypeParams<PCOF>;
  purchaseChangeOrderLine?: CreatePurchaseChangeOrderLineTypeParams<PCOLF>;
  organization: {
    db: {
      company: OrganizationDB["company"];
      site: OrganizationDB["site"];
    };
  };
  businessPartner: {
    db: {
      businessPartner: BusinessPartnerDB["businessPartner"];
      partnerRole: BusinessPartnerDB["partnerRole"];
      partnerIdentification: BusinessPartnerDB["partnerIdentification"];
    };
    queries: Pick<
      BusinessPartnerQueries,
      "getPartner" | "getPartnerRole" | "listPartnerIdentificationsByPartner"
    >;
  };
  itemManagement: {
    db: {
      item: ItemManagementDB["item"];
    };
    queries: Pick<ItemManagementQueries, "getItem">;
  };
  primitives: {
    db: {
      currency: PrimitivesDB["currency"];
      unit: PrimitivesDB["unit"];
    };
    queries: Pick<PrimitivesQueries, "getUnit">;
  };
  inventory: {
    commands: {
      createStockMovement: InventoryCommands["createStockMovement"];
    };
  };
  userManagement: {
    db: {
      user: UserManagementDB["user"];
    };
  };
}

/* @__NO_SIDE_EFFECTS__ */
export const defineModule = <
  const SPF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const PTF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const PLF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const PRF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const POF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const POLF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const GRF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const GRLF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const PBF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const PBLF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const PRQF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const PRQLF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const PCOF extends Record<string, TailorAnyDBField> = Record<never, never>,
  const PCOLF extends Record<string, TailorAnyDBField> = Record<never, never>,
>(
  params: DefineModuleParams<
    SPF,
    PTF,
    PLF,
    PRF,
    POF,
    POLF,
    GRF,
    GRLF,
    PBF,
    PBLF,
    PRQF,
    PRQLF,
    PCOF,
    PCOLF
  >,
) => {
  const purchasePaymentTermDb = createPurchasePaymentTermType({
    ...params.purchasePaymentTerm,
    companyType: params.organization.db.company,
  });
  const purchasePaymentTermLineDb = createPurchasePaymentTermLineType();
  const supplierProfileDb = createSupplierProfileType({
    ...params.supplierProfile,
    companyType: params.organization.db.company,
    supplierType: params.businessPartner.db.businessPartner,
  });
  const purchasePriceListDb = createPurchasePriceListType({
    ...params.purchasePriceList,
    companyType: params.organization.db.company,
    supplierType: params.businessPartner.db.businessPartner,
  });
  const purchasePriceRuleDb = createPurchasePriceRuleType({
    ...params.purchasePriceRule,
    itemType: params.itemManagement.db.item,
    currencyType: params.primitives.db.currency,
    unitType: params.primitives.db.unit,
  });
  const purchaseRequisitionDb = createPurchaseRequisitionType({
    ...params.purchaseRequisition,
    companyType: params.organization.db.company,
    userType: params.userManagement.db.user,
  });
  const purchaseRequisitionLineDb = createPurchaseRequisitionLineType({
    ...params.purchaseRequisitionLine,
    itemType: params.itemManagement.db.item,
    unitType: params.primitives.db.unit,
    suggestedSupplierType: params.businessPartner.db.businessPartner,
  });
  const purchaseOrderDb = createPurchaseOrderType({
    ...params.purchaseOrder,
    companyType: params.organization.db.company,
    supplierType: params.businessPartner.db.businessPartner,
    siteType: params.organization.db.site,
  });
  const purchaseOrderLineDb = createPurchaseOrderLineType({
    ...params.purchaseOrderLine,
    itemType: params.itemManagement.db.item,
    unitType: params.primitives.db.unit,
    siteType: params.organization.db.site,
  });
  const goodsReceiptDb = createGoodsReceiptType({
    ...params.goodsReceipt,
    companyType: params.organization.db.company,
    supplierType: params.businessPartner.db.businessPartner,
  });
  const goodsReceiptLineDb = createGoodsReceiptLineType({
    ...params.goodsReceiptLine,
    itemType: params.itemManagement.db.item,
    unitType: params.primitives.db.unit,
  });
  const purchaseBillDb = createPurchaseBillType({
    ...params.purchaseBill,
    companyType: params.organization.db.company,
    supplierType: params.businessPartner.db.businessPartner,
  });
  const purchaseBillLineDb = createPurchaseBillLineType({
    ...params.purchaseBillLine,
  });

  const purchaseRequisitionLineAllocationDb = createPurchaseRequisitionLineAllocationType();

  const threeWayMatchEventDb = createThreeWayMatchEventType();

  const purchaseChangeOrderDb = createPurchaseChangeOrderType({
    ...params.purchaseChangeOrder,
  });
  const purchaseChangeOrderLineDb = createPurchaseChangeOrderLineType({
    ...params.purchaseChangeOrderLine,
    itemType: params.itemManagement.db.item,
    unitType: params.primitives.db.unit,
    siteType: params.organization.db.site,
  });

  return {
    db: {
      supplierProfile: supplierProfileDb,
      purchasePaymentTerm: purchasePaymentTermDb,
      purchasePaymentTermLine: purchasePaymentTermLineDb,
      purchasePriceList: purchasePriceListDb,
      purchasePriceRule: purchasePriceRuleDb,
      purchaseOrder: purchaseOrderDb,
      purchaseOrderLine: purchaseOrderLineDb,
      goodsReceipt: goodsReceiptDb,
      goodsReceiptLine: goodsReceiptLineDb,
      purchaseBill: purchaseBillDb,
      purchaseBillLine: purchaseBillLineDb,
      purchaseRequisition: purchaseRequisitionDb,
      purchaseRequisitionLine: purchaseRequisitionLineDb,
      purchaseRequisitionLineAllocation: purchaseRequisitionLineAllocationDb,
      threeWayMatchEvent: threeWayMatchEventDb,
      purchaseChangeOrder: purchaseChangeOrderDb,
      purchaseChangeOrderLine: purchaseChangeOrderLineDb,
    },
    commands: {
      activatePurchasePaymentTerm: activatePurchasePaymentTerm(),
      activatePurchasePriceList: activatePurchasePriceList(),
      activatePurchasePriceRule: activatePurchasePriceRule(params.itemManagement.queries),
      applyPurchaseChangeOrder: applyPurchaseChangeOrder(),
      approvePurchaseChangeOrder: approvePurchaseChangeOrder(),
      approvePurchaseOrder: approvePurchaseOrder(
        params.businessPartner.queries,
        params.itemManagement.queries,
      ),
      approvePurchaseRequisition: approvePurchaseRequisition(),
      cancelGoodsReceipt: cancelGoodsReceipt(),
      cancelPurchaseBill: cancelPurchaseBill(),
      cancelPurchaseChangeOrder: cancelPurchaseChangeOrder(),
      cancelPurchaseOrder: cancelPurchaseOrder(),
      cancelPurchaseRequisition: cancelPurchaseRequisition(),
      closePurchaseOrder: closePurchaseOrder(),
      closePurchaseRequisition: closePurchaseRequisition(),
      convertPurchaseRequisitionToPurchaseOrder: convertPurchaseRequisitionToPurchaseOrder(
        params.businessPartner.queries,
        params.itemManagement.queries,
      ),
      createGoodsReceipt: createGoodsReceipt(),
      createPurchaseBill: createPurchaseBill(params.businessPartner.queries),
      createPurchaseChangeOrder: createPurchaseChangeOrder(),
      createPurchaseOrder: createPurchaseOrder(
        params.businessPartner.queries,
        params.itemManagement.queries,
      ),
      createPurchasePaymentTerm: createPurchasePaymentTerm(),
      createPurchaseRequisition: createPurchaseRequisition(params.businessPartner.queries),
      createPurchasePriceList: createPurchasePriceList(params.businessPartner.queries),
      createPurchasePriceRule: createPurchasePriceRule(params.itemManagement.queries),
      deactivatePurchasePaymentTerm: deactivatePurchasePaymentTerm(),
      deactivatePurchasePriceList: deactivatePurchasePriceList(),
      deactivatePurchasePriceRule: deactivatePurchasePriceRule(),
      matchPurchaseBill: matchPurchaseBill(),
      postGoodsReceipt: postGoodsReceipt(
        params.businessPartner.queries,
        params.itemManagement.queries,
        params.inventory.commands,
      ),
      recallPurchaseRequisition: recallPurchaseRequisition(),
      rejectPurchaseChangeOrder: rejectPurchaseChangeOrder(),
      rejectPurchaseOrder: rejectPurchaseOrder(),
      rejectPurchaseRequisition: rejectPurchaseRequisition(),
      releasePurchaseBill: releasePurchaseBill(),
      setSupplierDefaultPurchasePaymentTerm: setSupplierDefaultPurchasePaymentTerm(
        params.businessPartner.queries,
      ),
      submitPurchaseChangeOrder: submitPurchaseChangeOrder(),
      submitPurchaseOrder: submitPurchaseOrder(params.businessPartner.queries),
      submitPurchaseRequisition: submitPurchaseRequisition(),
      updateGoodsReceipt: updateGoodsReceipt(),
      updatePurchaseBill: updatePurchaseBill(),
      updatePurchaseOrder: updatePurchaseOrder(params.itemManagement.queries),
      updatePurchasePaymentTerm: updatePurchasePaymentTerm(),
      updatePurchasePriceList: updatePurchasePriceList(),
      updatePurchaseRequisition: updatePurchaseRequisition(params.businessPartner.queries),
      updatePurchaseChangeOrder: updatePurchaseChangeOrder(),
      updatePurchasePriceRule: updatePurchasePriceRule(params.itemManagement.queries),
    },
    queries: {
      getPurchaseChangeOrder,
      calculatePurchaseBillDueSchedule,
      calculatePurchasePrice,
      getGoodsReceipt,
      getPurchaseBill,
      getPurchaseOrder,
      getPurchasePaymentTerm,
      getPurchaseRequisition,
      getPurchasePriceList,
      getSupplierProfile,
    },
  };
};
