import { type TailorAnyDBField } from "@tailor-platform/sdk";
import type { defineModule as defineOrganizationModule } from "../organization";
import type { defineModule as definePrimitivesModule } from "../primitives";
import type { TemplateProvider } from "./command/createChartOfAccounts";
// Commands
import { createChartOfAccounts } from "./command/createChartOfAccounts.generated";
import { updateChartOfAccounts } from "./command/updateChartOfAccounts.generated";
import { activateChartOfAccounts } from "./command/activateChartOfAccounts.generated";
import { deactivateChartOfAccounts } from "./command/deactivateChartOfAccounts.generated";
import { deleteChartOfAccounts } from "./command/deleteChartOfAccounts.generated";
import { createAccountGroup } from "./command/createAccountGroup.generated";
import { updateAccountGroup } from "./command/updateAccountGroup.generated";
import { moveAccountGroup } from "./command/moveAccountGroup.generated";
import { deleteAccountGroup } from "./command/deleteAccountGroup.generated";
import { createAccount } from "./command/createAccount.generated";
import { updateAccount } from "./command/updateAccount.generated";
import { activateAccount } from "./command/activateAccount.generated";
import { deactivateAccount } from "./command/deactivateAccount.generated";
import { reactivateAccount } from "./command/reactivateAccount.generated";
import { deleteAccount } from "./command/deleteAccount.generated";
// Queries
import { getChartOfAccounts } from "./query/getChartOfAccounts.generated";
import { getAccount } from "./query/getAccount.generated";
import { getAccountGroup } from "./query/getAccountGroup.generated";
import { listAccounts } from "./query/listAccounts.generated";
import { listUnassignedAccounts } from "./query/listUnassignedAccounts.generated";
import { listAccountGroups } from "./query/listAccountGroups.generated";
import { detectCircularReference } from "./query/detectCircularReference.generated";
// DB types
import {
  createChartOfAccountsType,
  type CreateChartOfAccountsTypeParams,
} from "./db/chartOfAccounts";
import { createAccountGroupType, type CreateAccountGroupTypeParams } from "./db/accountGroup";
import { createAccountType, type CreateAccountTypeParams } from "./db/account";
import { type EmptyFields, type FieldsToInsertable } from "@tailor-platform/erp-kit/module";

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

type PrimitivesModule = ReturnType<typeof definePrimitivesModule>;
type PrimitivesDB = PrimitivesModule["db"];
export type PrimitivesQueries = PrimitivesModule["queries"];

export interface DefineModuleParams<
  COAF extends Record<string, TailorAnyDBField>,
  AGF extends Record<string, TailorAnyDBField>,
  AF extends Record<string, TailorAnyDBField>,
> {
  chartOfAccounts?: CreateChartOfAccountsTypeParams<COAF>;
  accountGroup?: CreateAccountGroupTypeParams<AGF>;
  account?: CreateAccountTypeParams<AF>;
  organization: {
    db: { company: OrganizationDB["company"] };
    queries: Pick<OrganizationQueries, "getCompany">;
  };
  primitives: {
    db: { currency: PrimitivesDB["currency"] };
    queries: Pick<PrimitivesQueries, "getCurrency">;
  };
  templateProvider?: TemplateProvider;
}

/* @__NO_SIDE_EFFECTS__ */
export const defineModule = <
  const COAF extends Record<string, TailorAnyDBField> = EmptyFields,
  const AGF extends Record<string, TailorAnyDBField> = EmptyFields,
  const AF extends Record<string, TailorAnyDBField> = EmptyFields,
>(
  params: DefineModuleParams<COAF, AGF, AF>,
) => {
  const chartOfAccountsDb = createChartOfAccountsType({
    ...params.chartOfAccounts,
    companyType: params.organization.db.company,
    currencyType: params.primitives.db.currency,
  });
  const accountGroupDb = createAccountGroupType({
    ...params.accountGroup,
    chartOfAccountsType: chartOfAccountsDb,
  });
  const accountDb = createAccountType({
    ...params.account,
    chartOfAccountsType: chartOfAccountsDb,
    accountGroupType: accountGroupDb,
    currencyType: params.primitives.db.currency,
  });

  return {
    db: {
      chartOfAccounts: chartOfAccountsDb,
      accountGroup: accountGroupDb,
      account: accountDb,
    },
    commands: {
      createChartOfAccounts: createChartOfAccounts<FieldsToInsertable<COAF>>(
        params.organization.queries,
        params.templateProvider,
      ),
      updateChartOfAccounts: updateChartOfAccounts<FieldsToInsertable<COAF>>(),
      activateChartOfAccounts: activateChartOfAccounts(),
      deactivateChartOfAccounts: deactivateChartOfAccounts(),
      deleteChartOfAccounts: deleteChartOfAccounts(),
      createAccountGroup: createAccountGroup<FieldsToInsertable<AGF>>(),
      updateAccountGroup: updateAccountGroup<FieldsToInsertable<AGF>>(),
      moveAccountGroup: moveAccountGroup(),
      deleteAccountGroup: deleteAccountGroup(),
      createAccount: createAccount<FieldsToInsertable<AF>>(params.primitives.queries),
      updateAccount: updateAccount<FieldsToInsertable<AF>>(params.primitives.queries),
      activateAccount: activateAccount(),
      deactivateAccount: deactivateAccount(),
      reactivateAccount: reactivateAccount(),
      deleteAccount: deleteAccount(),
    },
    queries: {
      getChartOfAccounts,
      getAccount,
      getAccountGroup,
      listAccounts,
      listUnassignedAccounts,
      listAccountGroups,
      detectCircularReference,
    },
  };
};
