import { type EmptyFields } from "@tailor-platform/erp-kit/core";
import type { TailorAnyDBField } from "@tailor-platform/sdk";
import type { defineModule as defineAccountingEventModule } from "../accounting-event";
import type { defineModule as defineBusinessPartnerModule } from "../business-partner";
import type { defineModule as defineCoaManagementModule } from "../coa-management";
import type { defineModule as defineInventoryModule } from "../inventory";
import type { defineModule as defineOrganizationModule } from "../organization";
import type { defineModule as definePrimitivesModule } from "../primitives";
import type { defineModule as definePurchaseModule } from "../purchase";
import { cancelAccountPayableDocument } from "./command/cancelAccountPayableDocument.generated";
import { correctAccountPayableDocument } from "./command/correctAccountPayableDocument.generated";
import { createAccountPayableDocument } from "./command/createAccountPayableDocument.generated";
import { createInvoiceToleranceConfig } from "./command/createInvoiceToleranceConfig.generated";
import { postAccountPayableDocument } from "./command/postAccountPayableDocument.generated";
import { registerAccountPayableDocument } from "./command/registerAccountPayableDocument.generated";
import { releaseAccountPayableDocumentHold } from "./command/releaseAccountPayableDocumentHold.generated";
import { updateAccountPayableDocument } from "./command/updateAccountPayableDocument.generated";
import { updateInvoiceToleranceConfig } from "./command/updateInvoiceToleranceConfig.generated";
import {
  createAccountPayableDistributionLineType,
  type CreateAccountPayableDistributionLineTypeParams,
} from "./db/accountPayableDistributionLine";
import {
  createAccountPayableDocumentType,
  type CreateAccountPayableDocumentTypeParams,
} from "./db/accountPayableDocument";
import {
  createAccountPayableDocumentHoldType,
  type CreateAccountPayableDocumentHoldTypeParams,
} from "./db/accountPayableDocumentHold";
import {
  createAccountPayableDocumentLineType,
  type CreateAccountPayableDocumentLineTypeParams,
} from "./db/accountPayableDocumentLine";
import {
  createAccountPayableDueScheduleLineType,
  type CreateAccountPayableDueScheduleLineTypeParams,
} from "./db/accountPayableDueScheduleLine";
import {
  createInvoiceToleranceConfigType,
  type CreateInvoiceToleranceConfigTypeParams,
} from "./db/invoiceToleranceConfig";

type OrganizationModule = ReturnType<typeof defineOrganizationModule>;
type OrganizationDB = OrganizationModule["db"];
export type OrganizationQueries = OrganizationModule["queries"];
type BusinessPartnerModule = ReturnType<typeof defineBusinessPartnerModule>;
type BusinessPartnerDB = BusinessPartnerModule["db"];
export type BusinessPartnerQueries = BusinessPartnerModule["queries"];
type PrimitivesModule = ReturnType<typeof definePrimitivesModule>;
type PrimitivesDB = PrimitivesModule["db"];
export type PrimitivesQueries = PrimitivesModule["queries"];
type AccountingEventModule = ReturnType<typeof defineAccountingEventModule>;
export type AccountingEventCommands = AccountingEventModule["commands"];
type CoaManagementModule = ReturnType<typeof defineCoaManagementModule>;
type CoaManagementDB = CoaManagementModule["db"];
export type CoaManagementQueries = CoaManagementModule["queries"];
type PurchaseModule = ReturnType<typeof definePurchaseModule>;
type PurchaseDB = PurchaseModule["db"];
export type PurchaseCommands = PurchaseModule["commands"];
export type PurchaseQueries = PurchaseModule["queries"];
type InventoryModule = ReturnType<typeof defineInventoryModule>;
export type InventoryQueries = InventoryModule["queries"];

export interface DefineModuleParams<
  ApdF extends Record<string, TailorAnyDBField> = EmptyFields,
  ApdlF extends Record<string, TailorAnyDBField> = EmptyFields,
  ApdistF extends Record<string, TailorAnyDBField> = EmptyFields,
  ApdslF extends Record<string, TailorAnyDBField> = EmptyFields,
  ApdhF extends Record<string, TailorAnyDBField> = EmptyFields,
  ItcF extends Record<string, TailorAnyDBField> = EmptyFields,
> {
  accountPayableDocument?: CreateAccountPayableDocumentTypeParams<ApdF>;
  accountPayableDocumentLine?: CreateAccountPayableDocumentLineTypeParams<ApdlF>;
  accountPayableDistributionLine?: CreateAccountPayableDistributionLineTypeParams<ApdistF>;
  accountPayableDueScheduleLine?: CreateAccountPayableDueScheduleLineTypeParams<ApdslF>;
  accountPayableDocumentHold?: CreateAccountPayableDocumentHoldTypeParams<ApdhF>;
  invoiceToleranceConfig?: CreateInvoiceToleranceConfigTypeParams<ItcF>;
  organization: {
    db: {
      company: OrganizationDB["company"];
    };
    queries: Pick<OrganizationQueries, "getCompany">;
  };
  businessPartner: {
    db: {
      businessPartner: BusinessPartnerDB["businessPartner"];
    };
    queries: Pick<BusinessPartnerQueries, "getPartner">;
  };
  primitives: {
    db: {
      currency: PrimitivesDB["currency"];
      unit: PrimitivesDB["unit"];
    };
    queries: Pick<PrimitivesQueries, "getCurrency">;
  };
  accountingEvent: {
    commands: Pick<AccountingEventCommands, "postAccountingEvent">;
  };
  coaManagement: {
    db: {
      account: CoaManagementDB["account"];
    };
    queries: Pick<CoaManagementQueries, "getAccount" | "listAccounts">;
  };
  purchase: {
    db: {
      purchaseOrderLine: PurchaseDB["purchaseOrderLine"];
    };
    commands: Pick<PurchaseCommands, "recalculatePurchaseOrderBillingStatus">;
    queries: Pick<PurchaseQueries, "listPurchaseOrderLinesForMatching">;
  };
  inventory: {
    queries: Pick<InventoryQueries, "listPurchaseReceiptQuantitiesForMatching">;
  };
}

/* @__NO_SIDE_EFFECTS__ */
export const defineModule = <
  const ApdF extends Record<string, TailorAnyDBField> = EmptyFields,
  const ApdlF extends Record<string, TailorAnyDBField> = EmptyFields,
  const ApdistF extends Record<string, TailorAnyDBField> = EmptyFields,
  const ApdslF extends Record<string, TailorAnyDBField> = EmptyFields,
  const ApdhF extends Record<string, TailorAnyDBField> = EmptyFields,
  const ItcF extends Record<string, TailorAnyDBField> = EmptyFields,
>(
  params: DefineModuleParams<ApdF, ApdlF, ApdistF, ApdslF, ApdhF, ItcF>,
) => {
  const accountPayableDocumentDb = createAccountPayableDocumentType({
    ...params.accountPayableDocument,
    companyType: params.organization.db.company,
    businessPartnerType: params.businessPartner.db.businessPartner,
    currencyType: params.primitives.db.currency,
    accountType: params.coaManagement.db.account,
  });
  const accountPayableDocumentLineDb = createAccountPayableDocumentLineType({
    ...params.accountPayableDocumentLine,
    purchaseOrderLineType: params.purchase.db.purchaseOrderLine,
    unitType: params.primitives.db.unit,
  });
  const accountPayableDistributionLineDb = createAccountPayableDistributionLineType({
    ...params.accountPayableDistributionLine,
    accountType: params.coaManagement.db.account,
  });
  const accountPayableDueScheduleLineDb = createAccountPayableDueScheduleLineType({
    ...params.accountPayableDueScheduleLine,
  });
  const accountPayableDocumentHoldDb = createAccountPayableDocumentHoldType({
    ...params.accountPayableDocumentHold,
  });
  const invoiceToleranceConfigDb = createInvoiceToleranceConfigType({
    ...params.invoiceToleranceConfig,
    companyType: params.organization.db.company,
    supplierType: params.businessPartner.db.businessPartner,
  });

  return {
    db: {
      accountPayableDocument: accountPayableDocumentDb,
      accountPayableDocumentLine: accountPayableDocumentLineDb,
      accountPayableDistributionLine: accountPayableDistributionLineDb,
      accountPayableDueScheduleLine: accountPayableDueScheduleLineDb,
      accountPayableDocumentHold: accountPayableDocumentHoldDb,
      invoiceToleranceConfig: invoiceToleranceConfigDb,
    },
    commands: {
      cancelAccountPayableDocument: cancelAccountPayableDocument(params.purchase.commands),
      correctAccountPayableDocument: correctAccountPayableDocument(
        params.organization.queries,
        params.businessPartner.queries,
        params.primitives.queries,
        params.coaManagement.queries,
      ),
      createAccountPayableDocument: createAccountPayableDocument(
        params.organization.queries,
        params.businessPartner.queries,
        params.primitives.queries,
        params.coaManagement.queries,
      ),
      createInvoiceToleranceConfig: createInvoiceToleranceConfig(
        params.organization.queries,
        params.businessPartner.queries,
      ),
      postAccountPayableDocument: postAccountPayableDocument(
        params.primitives.queries,
        params.accountingEvent.commands,
        params.coaManagement.queries,
      ),
      registerAccountPayableDocument: registerAccountPayableDocument(
        params.purchase.queries,
        params.inventory.queries,
        params.purchase.commands,
      ),
      releaseAccountPayableDocumentHold: releaseAccountPayableDocumentHold(),
      updateAccountPayableDocument: updateAccountPayableDocument(
        params.primitives.queries,
        params.coaManagement.queries,
      ),
      updateInvoiceToleranceConfig: updateInvoiceToleranceConfig(),
    },
    queries: {},
  };
};
