import type { TailorAnyDBField } from "@tailor-platform/sdk";
import { type EmptyFields } from "@tailor-platform/erp-kit/module";
import type { defineModule as defineCoaManagementModule } from "../coa-management";
import type { defineModule as defineOrganizationModule } from "../organization";
import type { defineModule as definePrimitivesModule } from "../primitives";
import type { defineModule as defineUserManagementModule } from "../user-management";
import { addJournalLine } from "./command/addJournalLine.generated";
import { approveAndLockPeriod } from "./command/approveAndLockPeriod.generated";
import { beginClose } from "./command/beginClose.generated";
import { closePeriod } from "./command/closePeriod.generated";
import { createAccountingPeriod } from "./command/createAccountingPeriod.generated";
import { createFiscalYear } from "./command/createFiscalYear.generated";
import { createJournalEntry } from "./command/createJournalEntry.generated";
import { deleteAccountingPeriod } from "./command/deleteAccountingPeriod.generated";
import { deleteFiscalYear } from "./command/deleteFiscalYear.generated";
import { deleteJournalEntry } from "./command/deleteJournalEntry.generated";
import { executeYearEndClose } from "./command/executeYearEndClose.generated";
import { finalCloseAndLockPeriod } from "./command/finalCloseAndLockPeriod.generated";
import { finalizeFinancialStatement } from "./command/finalizeFinancialStatement.generated";
import { generateFinancialStatement } from "./command/generateFinancialStatement.generated";
import { generatePreliminaryStatements } from "./command/generatePreliminaryStatements.generated";
import { generateTrialBalance } from "./command/generateTrialBalance.generated";
import { initiatePeriodClose } from "./command/initiatePeriodClose.generated";
import { openForAdvanceEntry } from "./command/openForAdvanceEntry.generated";
import { openPeriod } from "./command/openPeriod.generated";
import { permanentlyClosePeriod } from "./command/permanentlyClosePeriod.generated";
import { postAdjustingEntries } from "./command/postAdjustingEntries.generated";
import { postJournalEntry } from "./command/postJournalEntry.generated";
import { processInventoryHandoff } from "./command/processInventoryHandoff.generated";
import { processManufacturingHandoff } from "./command/processManufacturingHandoff.generated";
import { processPurchaseHandoff } from "./command/processPurchaseHandoff.generated";
import { processSalesHandoff } from "./command/processSalesHandoff.generated";
import { regenerateFinancialStatement } from "./command/regenerateFinancialStatement.generated";
import { removeJournalLine } from "./command/removeJournalLine.generated";
import { reopenPeriod } from "./command/reopenPeriod.generated";
import { reverseJournalEntry } from "./command/reverseJournalEntry.generated";
import { revertSoftLock } from "./command/revertSoftLock.generated";
import { updateFiscalYear } from "./command/updateFiscalYear.generated";
import { updateJournalEntry } from "./command/updateJournalEntry.generated";
import { updateJournalLine } from "./command/updateJournalLine.generated";
import { verifySubledgerTransfers } from "./command/verifySubledgerTransfers.generated";
import { verifyTrialBalance } from "./command/verifyTrialBalance.generated";
import {
  createAccountingPeriodType,
  type CreateAccountingPeriodTypeParams,
} from "./db/accountingPeriod";
import {
  createFinancialStatementType,
  type CreateFinancialStatementTypeParams,
} from "./db/financialStatement";
import {
  createFinancialStatementLineItemType,
  type CreateFinancialStatementLineItemTypeParams,
} from "./db/financialStatementLineItem";
import { createFiscalYearType, type CreateFiscalYearTypeParams } from "./db/fiscalYear";
import { createJournalEntryType, type CreateJournalEntryTypeParams } from "./db/journalEntry";
import { createJournalLineType, type CreateJournalLineTypeParams } from "./db/journalLine";
import { createPeriodCloseType, type CreatePeriodCloseTypeParams } from "./db/periodClose";
import { createTrialBalanceType, type CreateTrialBalanceTypeParams } from "./db/trialBalance";
import {
  createTrialBalanceLineType,
  type CreateTrialBalanceLineTypeParams,
} from "./db/trialBalanceLine";
import { getAccountingPeriod } from "./query/getAccountingPeriod.generated";
import { getFinancialStatement } from "./query/getFinancialStatement.generated";
import { getFiscalYear } from "./query/getFiscalYear.generated";
import { getJournalEntry } from "./query/getJournalEntry.generated";
import { getPeriodByDate } from "./query/getPeriodByDate.generated";
import { getPeriodClose } from "./query/getPeriodClose.generated";
import { getSubledgerTransferStatus } from "./query/getSubledgerTransferStatus.generated";
import { getTrialBalance } from "./query/getTrialBalance.generated";
import { listAccountingPeriods } from "./query/listAccountingPeriods.generated";
import { listFinancialStatements } from "./query/listFinancialStatements.generated";
import { listFiscalYears } from "./query/listFiscalYears.generated";
import { listJournalEntries } from "./query/listJournalEntries.generated";
import { listPeriodCloses } from "./query/listPeriodCloses.generated";
import { listTrialBalances } from "./query/listTrialBalances.generated";

type OrganizationModule = ReturnType<typeof defineOrganizationModule>;
type OrganizationDB = OrganizationModule["db"];
type CoaManagementModule = ReturnType<typeof defineCoaManagementModule>;
type CoaManagementDB = CoaManagementModule["db"];
type PrimitivesModule = ReturnType<typeof definePrimitivesModule>;
type PrimitivesDB = PrimitivesModule["db"];
type UserManagementModule = ReturnType<typeof defineUserManagementModule>;
type UserManagementDB = UserManagementModule["db"];

export interface DefineModuleParams<
  FyF extends Record<string, TailorAnyDBField> = EmptyFields,
  ApF extends Record<string, TailorAnyDBField> = EmptyFields,
  JeF extends Record<string, TailorAnyDBField> = EmptyFields,
  JlF extends Record<string, TailorAnyDBField> = EmptyFields,
  PcF extends Record<string, TailorAnyDBField> = EmptyFields,
  TbF extends Record<string, TailorAnyDBField> = EmptyFields,
  TblF extends Record<string, TailorAnyDBField> = EmptyFields,
  FsF extends Record<string, TailorAnyDBField> = EmptyFields,
  FslF extends Record<string, TailorAnyDBField> = EmptyFields,
> {
  fiscalYear?: CreateFiscalYearTypeParams<FyF>;
  accountingPeriod?: CreateAccountingPeriodTypeParams<ApF>;
  journalEntry?: CreateJournalEntryTypeParams<JeF>;
  journalLine?: CreateJournalLineTypeParams<JlF>;
  periodClose?: CreatePeriodCloseTypeParams<PcF>;
  trialBalance?: CreateTrialBalanceTypeParams<TbF>;
  trialBalanceLine?: CreateTrialBalanceLineTypeParams<TblF>;
  financialStatement?: CreateFinancialStatementTypeParams<FsF>;
  financialStatementLineItem?: CreateFinancialStatementLineItemTypeParams<FslF>;
  organization: {
    db: {
      company: OrganizationDB["company"];
    };
  };
  coaManagement: {
    db: {
      account: CoaManagementDB["account"];
      accountGroup: CoaManagementDB["accountGroup"];
      chartOfAccounts: CoaManagementDB["chartOfAccounts"];
    };
  };
  primitives: {
    db: {
      currency: PrimitivesDB["currency"];
    };
  };
  userManagement: {
    db: {
      user: UserManagementDB["user"];
    };
  };
}

/* @__NO_SIDE_EFFECTS__ */
export const defineModule = <
  const FyF extends Record<string, TailorAnyDBField> = EmptyFields,
  const ApF extends Record<string, TailorAnyDBField> = EmptyFields,
  const JeF extends Record<string, TailorAnyDBField> = EmptyFields,
  const JlF extends Record<string, TailorAnyDBField> = EmptyFields,
  const PcF extends Record<string, TailorAnyDBField> = EmptyFields,
  const TbF extends Record<string, TailorAnyDBField> = EmptyFields,
  const TblF extends Record<string, TailorAnyDBField> = EmptyFields,
  const FsF extends Record<string, TailorAnyDBField> = EmptyFields,
  const FslF extends Record<string, TailorAnyDBField> = EmptyFields,
>(
  params: DefineModuleParams<FyF, ApF, JeF, JlF, PcF, TbF, TblF, FsF, FslF>,
) => {
  const fiscalYearDb = createFiscalYearType({
    ...params.fiscalYear,
    companyType: params.organization.db.company,
  });
  const accountingPeriodDb = createAccountingPeriodType({
    ...params.accountingPeriod,
    companyType: params.organization.db.company,
    fiscalYearType: fiscalYearDb,
  });
  const journalEntryDb = createJournalEntryType({
    ...params.journalEntry,
    companyType: params.organization.db.company,
    accountingPeriodType: accountingPeriodDb,
  });
  const journalLineDb = createJournalLineType({
    ...params.journalLine,
    journalEntryType: journalEntryDb,
    accountType: params.coaManagement.db.account,
  });
  const periodCloseDb = createPeriodCloseType({
    ...params.periodClose,
    accountingPeriodType: accountingPeriodDb,
    initiatedByUserType: params.userManagement.db.user,
    approvedByUserType: params.userManagement.db.user,
  });
  const trialBalanceDb = createTrialBalanceType({
    ...params.trialBalance,
    companyType: params.organization.db.company,
    accountingPeriodType: accountingPeriodDb,
    chartOfAccountsType: params.coaManagement.db.chartOfAccounts,
  });
  const trialBalanceLineDb = createTrialBalanceLineType({
    ...params.trialBalanceLine,
    trialBalanceType: trialBalanceDb,
    accountType: params.coaManagement.db.account,
    accountGroupType: params.coaManagement.db.accountGroup,
  });
  const financialStatementDb = createFinancialStatementType({
    ...params.financialStatement,
    companyType: params.organization.db.company,
    chartOfAccountsType: params.coaManagement.db.chartOfAccounts,
    trialBalanceType: trialBalanceDb,
  });
  const financialStatementLineItemDb = createFinancialStatementLineItemType({
    ...params.financialStatementLineItem,
    financialStatementType: financialStatementDb,
    accountType: params.coaManagement.db.account,
    accountGroupType: params.coaManagement.db.accountGroup,
  });

  return {
    db: {
      fiscalYear: fiscalYearDb,
      accountingPeriod: accountingPeriodDb,
      journalEntry: journalEntryDb,
      journalLine: journalLineDb,
      periodClose: periodCloseDb,
      trialBalance: trialBalanceDb,
      trialBalanceLine: trialBalanceLineDb,
      financialStatement: financialStatementDb,
      financialStatementLineItem: financialStatementLineItemDb,
    },
    commands: {
      addJournalLine: addJournalLine(),
      approveAndLockPeriod: approveAndLockPeriod(),
      beginClose: beginClose(),
      closePeriod: closePeriod(),
      createAccountingPeriod: createAccountingPeriod(),
      createFiscalYear: createFiscalYear(),
      createJournalEntry: createJournalEntry(),
      deleteAccountingPeriod: deleteAccountingPeriod(),
      deleteFiscalYear: deleteFiscalYear(),
      deleteJournalEntry: deleteJournalEntry(),
      executeYearEndClose: executeYearEndClose(),
      finalCloseAndLockPeriod: finalCloseAndLockPeriod(),
      finalizeFinancialStatement: finalizeFinancialStatement(),
      generateFinancialStatement: generateFinancialStatement(),
      generatePreliminaryStatements: generatePreliminaryStatements(),
      generateTrialBalance: generateTrialBalance(),
      initiatePeriodClose: initiatePeriodClose(),
      openForAdvanceEntry: openForAdvanceEntry(),
      openPeriod: openPeriod(),
      permanentlyClosePeriod: permanentlyClosePeriod(),
      postAdjustingEntries: postAdjustingEntries(),
      postJournalEntry: postJournalEntry(),
      processInventoryHandoff: processInventoryHandoff(),
      processManufacturingHandoff: processManufacturingHandoff(),
      processPurchaseHandoff: processPurchaseHandoff(),
      processSalesHandoff: processSalesHandoff(),
      regenerateFinancialStatement: regenerateFinancialStatement(),
      removeJournalLine: removeJournalLine(),
      reopenPeriod: reopenPeriod(),
      reverseJournalEntry: reverseJournalEntry(),
      revertSoftLock: revertSoftLock(),
      updateFiscalYear: updateFiscalYear(),
      updateJournalEntry: updateJournalEntry(),
      updateJournalLine: updateJournalLine(),
      verifySubledgerTransfers: verifySubledgerTransfers(),
      verifyTrialBalance: verifyTrialBalance(),
    },
    queries: {
      getAccountingPeriod,
      getFinancialStatement,
      getFiscalYear,
      getJournalEntry,
      getPeriodByDate,
      getPeriodClose,
      getSubledgerTransferStatus,
      getTrialBalance,
      listAccountingPeriods,
      listFinancialStatements,
      listFiscalYears,
      listJournalEntries,
      listPeriodCloses,
      listTrialBalances,
    },
  };
};
