import type { TailorAnyDBField } from "@tailor-platform/sdk";
import type { defineModule as defineBusinessPartnerModule } from "../business-partner";
import type { defineModule as defineItemManagementModule } from "../item-management";
import type { defineModule as defineOrganizationModule } from "../organization";
import type { defineModule as definePrimitivesModule } from "../primitives";
import { activateChannel } from "./command/activateChannel.generated";
import { activateListing } from "./command/activateListing.generated";
import { activateSalesPaymentTerm } from "./command/activateSalesPaymentTerm.generated";
import { activateSalesPriceList } from "./command/activateSalesPriceList.generated";
import { activateSalesPriceRule } from "./command/activateSalesPriceRule.generated";
import { cancelChannelOrder } from "./command/cancelChannelOrder.generated";
import { cancelSalesInvoice } from "./command/cancelSalesInvoice.generated";
import { cancelSalesOrder } from "./command/cancelSalesOrder.generated";
import { cancelSyncJob } from "./command/cancelSyncJob.generated";
import { closeSalesOrder } from "./command/closeSalesOrder.generated";
import { confirmSalesOrder } from "./command/confirmSalesOrder.generated";
import { convertChannelOrder } from "./command/convertChannelOrder.generated";
import { createChannel } from "./command/createChannel.generated";
import { createListing } from "./command/createListing.generated";
import { createSalesCreditNote } from "./command/createSalesCreditNote.generated";
import { createSalesInvoice } from "./command/createSalesInvoice.generated";
import { createSalesOrder } from "./command/createSalesOrder.generated";
import { createSalesPaymentTerm } from "./command/createSalesPaymentTerm.generated";
import { createSalesPriceList } from "./command/createSalesPriceList.generated";
import { createSalesPriceRule } from "./command/createSalesPriceRule.generated";
import { createShipment } from "./command/createShipment.generated";
import { deactivateChannel } from "./command/deactivateChannel.generated";
import { deactivateSalesPaymentTerm } from "./command/deactivateSalesPaymentTerm.generated";
import { deactivateSalesPriceList } from "./command/deactivateSalesPriceList.generated";
import { deactivateSalesPriceRule } from "./command/deactivateSalesPriceRule.generated";
import { issueSalesCreditNote } from "./command/issueSalesCreditNote.generated";
import { issueSalesInvoice } from "./command/issueSalesInvoice.generated";
import { markChannelOrderException } from "./command/markChannelOrderException.generated";
import { pauseListing } from "./command/pauseListing.generated";
import { placeSalesOrderOnCreditHold } from "./command/placeSalesOrderOnCreditHold.generated";
import { postShipment } from "./command/postShipment.generated";
import { recordChannelOrder } from "./command/recordChannelOrder.generated";
import { rejectSalesOrder } from "./command/rejectSalesOrder.generated";
import { releaseSalesOrderCreditHold } from "./command/releaseSalesOrderCreditHold.generated";
import { retireListing } from "./command/retireListing.generated";
import { retrySyncJob } from "./command/retrySyncJob.generated";
import { sendSalesInvoice } from "./command/sendSalesInvoice.generated";
import { startSyncJob } from "./command/startSyncJob.generated";
import { submitSalesOrder } from "./command/submitSalesOrder.generated";
import { updateChannel } from "./command/updateChannel.generated";
import { updateListing } from "./command/updateListing.generated";
import { updateSalesCreditNote } from "./command/updateSalesCreditNote.generated";
import { updateSalesInvoice } from "./command/updateSalesInvoice.generated";
import { updateSalesOrder } from "./command/updateSalesOrder.generated";
import { updateSalesPaymentTerm } from "./command/updateSalesPaymentTerm.generated";
import { updateSalesPriceList } from "./command/updateSalesPriceList.generated";
import { updateSalesPriceRule } from "./command/updateSalesPriceRule.generated";
import { updateShipment } from "./command/updateShipment.generated";
import { createChannelType, type CreateChannelTypeParams } from "./db/channel";
import { createChannelOrderType, type CreateChannelOrderTypeParams } from "./db/channelOrder";
import {
  createChannelOrderLineType,
  type CreateChannelOrderLineTypeParams,
} from "./db/channelOrderLine";
import { createListingType, type CreateListingTypeParams } from "./db/listing";
import {
  createSalesCreditNoteType,
  type CreateSalesCreditNoteTypeParams,
} from "./db/salesCreditNote";
import {
  createSalesCreditNoteLineType,
  type CreateSalesCreditNoteLineTypeParams,
} from "./db/salesCreditNoteLine";
import { createSalesInvoiceType, type CreateSalesInvoiceTypeParams } from "./db/salesInvoice";
import {
  createSalesInvoiceLineType,
  type CreateSalesInvoiceLineTypeParams,
} from "./db/salesInvoiceLine";
import { createSalesOrderType, type CreateSalesOrderTypeParams } from "./db/salesOrder";
import { createSalesOrderLineType, type CreateSalesOrderLineTypeParams } from "./db/salesOrderLine";
import {
  createSalesPaymentTermType,
  type CreateSalesPaymentTermTypeParams,
} from "./db/salesPaymentTerm";
import { createSalesPriceListType, type CreateSalesPriceListTypeParams } from "./db/salesPriceList";
import { createSalesPriceRuleType, type CreateSalesPriceRuleTypeParams } from "./db/salesPriceRule";
import { createShipmentType, type CreateShipmentTypeParams } from "./db/shipment";
import { createShipmentLineType, type CreateShipmentLineTypeParams } from "./db/shipmentLine";
import { createSyncJobType, type CreateSyncJobTypeParams } from "./db/syncJob";
import { calculateInvoiceDueSchedule } from "./query/calculateInvoiceDueSchedule.generated";
import { getApplicableSalesPrice } from "./query/getApplicableSalesPrice.generated";
import { getChannel } from "./query/getChannel.generated";
import { getChannelOrder } from "./query/getChannelOrder.generated";
import { getListing } from "./query/getListing.generated";
import { getListingByExternalIdentifier } from "./query/getListingByExternalIdentifier.generated";
import { getSalesCreditNote } from "./query/getSalesCreditNote.generated";
import { getSalesInvoice } from "./query/getSalesInvoice.generated";
import { getSalesOrder } from "./query/getSalesOrder.generated";
import { getSalesPaymentTerm } from "./query/getSalesPaymentTerm.generated";
import { getSalesPriceList } from "./query/getSalesPriceList.generated";
import { getShipment } from "./query/getShipment.generated";
import { getSyncJob } from "./query/getSyncJob.generated";
import { listChannelOrdersByStatus } from "./query/listChannelOrdersByStatus.generated";
import { listChannels } from "./query/listChannels.generated";
import { listListingsByChannel } from "./query/listListingsByChannel.generated";
import { listSalesCreditNotesByInvoice } from "./query/listSalesCreditNotesByInvoice.generated";
import { listSalesInvoicesBySalesOrder } from "./query/listSalesInvoicesBySalesOrder.generated";
import { listSalesOrders } from "./query/listSalesOrders.generated";
import { listSalesPaymentTerms } from "./query/listSalesPaymentTerms.generated";
import { listSalesPriceLists } from "./query/listSalesPriceLists.generated";
import { listSalesPriceRulesByPriceList } from "./query/listSalesPriceRulesByPriceList.generated";
import { listShipmentsBySalesOrder } from "./query/listShipmentsBySalesOrder.generated";
import { listSyncJobs } from "./query/listSyncJobs.generated";
import { type EmptyFields } from "@tailor-platform/erp-kit/module";

type OrganizationModule = ReturnType<typeof defineOrganizationModule>;
type OrganizationDB = OrganizationModule["db"];
type BusinessPartnerModule = ReturnType<typeof defineBusinessPartnerModule>;
type BusinessPartnerDB = BusinessPartnerModule["db"];
type ItemManagementModule = ReturnType<typeof defineItemManagementModule>;
type ItemManagementDB = ItemManagementModule["db"];
type PrimitivesModule = ReturnType<typeof definePrimitivesModule>;
type PrimitivesDB = PrimitivesModule["db"];

export interface DefineModuleParams<
  ChF extends Record<string, TailorAnyDBField> = EmptyFields,
  LiF extends Record<string, TailorAnyDBField> = EmptyFields,
  PtF extends Record<string, TailorAnyDBField> = EmptyFields,
  PlF extends Record<string, TailorAnyDBField> = EmptyFields,
  PrF extends Record<string, TailorAnyDBField> = EmptyFields,
  SoF extends Record<string, TailorAnyDBField> = EmptyFields,
  SolF extends Record<string, TailorAnyDBField> = EmptyFields,
  ShF extends Record<string, TailorAnyDBField> = EmptyFields,
  ShlF extends Record<string, TailorAnyDBField> = EmptyFields,
  SiF extends Record<string, TailorAnyDBField> = EmptyFields,
  SilF extends Record<string, TailorAnyDBField> = EmptyFields,
  ScF extends Record<string, TailorAnyDBField> = EmptyFields,
  SclF extends Record<string, TailorAnyDBField> = EmptyFields,
  CoF extends Record<string, TailorAnyDBField> = EmptyFields,
  ColF extends Record<string, TailorAnyDBField> = EmptyFields,
  SjF extends Record<string, TailorAnyDBField> = EmptyFields,
> {
  channel?: CreateChannelTypeParams<ChF>;
  listing?: CreateListingTypeParams<LiF>;
  salesPaymentTerm?: CreateSalesPaymentTermTypeParams<PtF>;
  salesPriceList?: CreateSalesPriceListTypeParams<PlF>;
  salesPriceRule?: CreateSalesPriceRuleTypeParams<PrF>;
  salesOrder?: CreateSalesOrderTypeParams<SoF>;
  salesOrderLine?: CreateSalesOrderLineTypeParams<SolF>;
  shipment?: CreateShipmentTypeParams<ShF>;
  shipmentLine?: CreateShipmentLineTypeParams<ShlF>;
  salesInvoice?: CreateSalesInvoiceTypeParams<SiF>;
  salesInvoiceLine?: CreateSalesInvoiceLineTypeParams<SilF>;
  salesCreditNote?: CreateSalesCreditNoteTypeParams<ScF>;
  salesCreditNoteLine?: CreateSalesCreditNoteLineTypeParams<SclF>;
  channelOrder?: CreateChannelOrderTypeParams<CoF>;
  channelOrderLine?: CreateChannelOrderLineTypeParams<ColF>;
  syncJob?: CreateSyncJobTypeParams<SjF>;
  organization: {
    db: {
      company: OrganizationDB["company"];
      site: OrganizationDB["site"];
    };
  };
  businessPartner: {
    db: {
      businessPartner: BusinessPartnerDB["businessPartner"];
      partnerRole: BusinessPartnerDB["partnerRole"];
    };
  };
  itemManagement: {
    db: {
      item: ItemManagementDB["item"];
    };
  };
  primitives: {
    db: {
      currency: PrimitivesDB["currency"];
      unit: PrimitivesDB["unit"];
    };
  };
}

/* @__NO_SIDE_EFFECTS__ */
export const defineModule = <
  const ChF extends Record<string, TailorAnyDBField> = EmptyFields,
  const LiF extends Record<string, TailorAnyDBField> = EmptyFields,
  const PtF extends Record<string, TailorAnyDBField> = EmptyFields,
  const PlF extends Record<string, TailorAnyDBField> = EmptyFields,
  const PrF extends Record<string, TailorAnyDBField> = EmptyFields,
  const SoF extends Record<string, TailorAnyDBField> = EmptyFields,
  const SolF extends Record<string, TailorAnyDBField> = EmptyFields,
  const ShF extends Record<string, TailorAnyDBField> = EmptyFields,
  const ShlF extends Record<string, TailorAnyDBField> = EmptyFields,
  const SiF extends Record<string, TailorAnyDBField> = EmptyFields,
  const SilF extends Record<string, TailorAnyDBField> = EmptyFields,
  const ScF extends Record<string, TailorAnyDBField> = EmptyFields,
  const SclF extends Record<string, TailorAnyDBField> = EmptyFields,
  const CoF extends Record<string, TailorAnyDBField> = EmptyFields,
  const ColF extends Record<string, TailorAnyDBField> = EmptyFields,
  const SjF extends Record<string, TailorAnyDBField> = EmptyFields,
>(
  params: DefineModuleParams<
    ChF,
    LiF,
    PtF,
    PlF,
    PrF,
    SoF,
    SolF,
    ShF,
    ShlF,
    SiF,
    SilF,
    ScF,
    SclF,
    CoF,
    ColF,
    SjF
  >,
) => {
  const channelDb = createChannelType({
    ...params.channel,
    companyType: params.organization.db.company,
  });
  const salesPaymentTermDb = createSalesPaymentTermType({
    ...params.salesPaymentTerm,
    companyType: params.organization.db.company,
  });
  const salesPriceListDb = createSalesPriceListType({
    ...params.salesPriceList,
    companyType: params.organization.db.company,
    customerType: params.businessPartner.db.businessPartner,
    channelType: channelDb,
  });
  const listingDb = createListingType({
    ...params.listing,
    companyType: params.organization.db.company,
    channelType: channelDb,
    itemType: params.itemManagement.db.item,
    salesPriceListType: salesPriceListDb,
  });
  const salesPriceRuleDb = createSalesPriceRuleType({
    ...params.salesPriceRule,
    salesPriceListType: salesPriceListDb,
    itemType: params.itemManagement.db.item,
    customerType: params.businessPartner.db.businessPartner,
    channelType: channelDb,
    currencyType: params.primitives.db.currency,
    unitType: params.primitives.db.unit,
  });
  const salesOrderDb = createSalesOrderType({
    ...params.salesOrder,
    companyType: params.organization.db.company,
    customerType: params.businessPartner.db.businessPartner,
    channelType: channelDb,
    paymentTermType: salesPaymentTermDb,
  });
  const salesOrderLineDb = createSalesOrderLineType({
    ...params.salesOrderLine,
    salesOrderType: salesOrderDb,
    itemType: params.itemManagement.db.item,
    currencyType: params.primitives.db.currency,
    unitType: params.primitives.db.unit,
    salesPriceRuleType: salesPriceRuleDb,
  });
  const shipmentDb = createShipmentType({
    ...params.shipment,
    companyType: params.organization.db.company,
    salesOrderType: salesOrderDb,
    customerType: params.businessPartner.db.businessPartner,
    siteType: params.organization.db.site,
  });
  const shipmentLineDb = createShipmentLineType({
    ...params.shipmentLine,
    shipmentType: shipmentDb,
    salesOrderLineType: salesOrderLineDb,
    unitType: params.primitives.db.unit,
  });
  const salesInvoiceDb = createSalesInvoiceType({
    ...params.salesInvoice,
    companyType: params.organization.db.company,
    customerType: params.businessPartner.db.businessPartner,
    salesOrderType: salesOrderDb,
    paymentTermType: salesPaymentTermDb,
    shipmentType: shipmentDb,
  });
  const salesInvoiceLineDb = createSalesInvoiceLineType({
    ...params.salesInvoiceLine,
    salesInvoiceType: salesInvoiceDb,
    salesOrderLineType: salesOrderLineDb,
    shipmentLineType: shipmentLineDb,
  });
  const salesCreditNoteDb = createSalesCreditNoteType({
    ...params.salesCreditNote,
    companyType: params.organization.db.company,
    customerType: params.businessPartner.db.businessPartner,
    salesInvoiceType: salesInvoiceDb,
  });
  const salesCreditNoteLineDb = createSalesCreditNoteLineType({
    ...params.salesCreditNoteLine,
    salesCreditNoteType: salesCreditNoteDb,
    salesInvoiceLineType: salesInvoiceLineDb,
  });
  const syncJobDb = createSyncJobType({
    ...params.syncJob,
    companyType: params.organization.db.company,
    channelType: channelDb,
  });
  const channelOrderDb = createChannelOrderType({
    ...params.channelOrder,
    companyType: params.organization.db.company,
    channelType: channelDb,
    customerType: params.businessPartner.db.businessPartner,
    salesOrderType: salesOrderDb,
    currencyType: params.primitives.db.currency,
    syncJobType: syncJobDb,
  });
  const channelOrderLineDb = createChannelOrderLineType({
    ...params.channelOrderLine,
    channelOrderType: channelOrderDb,
    listingType: listingDb,
    itemType: params.itemManagement.db.item,
    currencyType: params.primitives.db.currency,
    unitType: params.primitives.db.unit,
  });

  return {
    db: {
      channel: channelDb,
      listing: listingDb,
      salesPaymentTerm: salesPaymentTermDb,
      salesPriceList: salesPriceListDb,
      salesPriceRule: salesPriceRuleDb,
      salesOrder: salesOrderDb,
      salesOrderLine: salesOrderLineDb,
      shipment: shipmentDb,
      shipmentLine: shipmentLineDb,
      salesInvoice: salesInvoiceDb,
      salesInvoiceLine: salesInvoiceLineDb,
      salesCreditNote: salesCreditNoteDb,
      salesCreditNoteLine: salesCreditNoteLineDb,
      channelOrder: channelOrderDb,
      channelOrderLine: channelOrderLineDb,
      syncJob: syncJobDb,
    },
    commands: {
      activateChannel: activateChannel(),
      activateListing: activateListing(),
      activateSalesPaymentTerm: activateSalesPaymentTerm(),
      activateSalesPriceList: activateSalesPriceList(),
      activateSalesPriceRule: activateSalesPriceRule(),
      cancelChannelOrder: cancelChannelOrder(),
      cancelSalesInvoice: cancelSalesInvoice(),
      cancelSalesOrder: cancelSalesOrder(),
      cancelSyncJob: cancelSyncJob(),
      closeSalesOrder: closeSalesOrder(),
      confirmSalesOrder: confirmSalesOrder(),
      convertChannelOrder: convertChannelOrder(),
      createChannel: createChannel(),
      createListing: createListing(),
      createSalesCreditNote: createSalesCreditNote(),
      createSalesInvoice: createSalesInvoice(),
      createSalesOrder: createSalesOrder(),
      createSalesPaymentTerm: createSalesPaymentTerm(),
      createSalesPriceList: createSalesPriceList(),
      createSalesPriceRule: createSalesPriceRule(),
      createShipment: createShipment(),
      deactivateChannel: deactivateChannel(),
      deactivateSalesPaymentTerm: deactivateSalesPaymentTerm(),
      deactivateSalesPriceList: deactivateSalesPriceList(),
      deactivateSalesPriceRule: deactivateSalesPriceRule(),
      issueSalesCreditNote: issueSalesCreditNote(),
      issueSalesInvoice: issueSalesInvoice(),
      markChannelOrderException: markChannelOrderException(),
      pauseListing: pauseListing(),
      placeSalesOrderOnCreditHold: placeSalesOrderOnCreditHold(),
      postShipment: postShipment(),
      recordChannelOrder: recordChannelOrder(),
      rejectSalesOrder: rejectSalesOrder(),
      releaseSalesOrderCreditHold: releaseSalesOrderCreditHold(),
      retireListing: retireListing(),
      retrySyncJob: retrySyncJob(),
      sendSalesInvoice: sendSalesInvoice(),
      startSyncJob: startSyncJob(),
      submitSalesOrder: submitSalesOrder(),
      updateChannel: updateChannel(),
      updateListing: updateListing(),
      updateSalesCreditNote: updateSalesCreditNote(),
      updateSalesInvoice: updateSalesInvoice(),
      updateSalesOrder: updateSalesOrder(),
      updateSalesPaymentTerm: updateSalesPaymentTerm(),
      updateSalesPriceList: updateSalesPriceList(),
      updateSalesPriceRule: updateSalesPriceRule(),
      updateShipment: updateShipment(),
    },
    queries: {
      calculateInvoiceDueSchedule,
      getApplicableSalesPrice,
      getChannel,
      getChannelOrder,
      getListing,
      getListingByExternalIdentifier,
      getSalesCreditNote,
      getSalesInvoice,
      getSalesOrder,
      getSalesPaymentTerm,
      getSalesPriceList,
      getShipment,
      getSyncJob,
      listChannelOrdersByStatus,
      listChannels,
      listListingsByChannel,
      listSalesCreditNotesByInvoice,
      listSalesInvoicesBySalesOrder,
      listSalesOrders,
      listSalesPaymentTerms,
      listSalesPriceLists,
      listSalesPriceRulesByPriceList,
      listShipmentsBySalesOrder,
      listSyncJobs,
    },
  };
};
