import { type TailorAnyDBField } from "@tailor-platform/sdk";
import type { defineModule as definePrimitivesModule } from "../primitives";
import { createItem } from "./command/createItem.generated";
import { updateItem } from "./command/updateItem.generated";
import { activateItem } from "./command/activateItem.generated";
import { deactivateItem } from "./command/deactivateItem.generated";
import { reactivateItem } from "./command/reactivateItem.generated";
import { deleteItem } from "./command/deleteItem.generated";
import { createTaxonomyNode } from "./command/createTaxonomyNode.generated";
import { updateTaxonomyNode } from "./command/updateTaxonomyNode.generated";
import { moveTaxonomyNode } from "./command/moveTaxonomyNode.generated";
import { deleteTaxonomyNode } from "./command/deleteTaxonomyNode.generated";
import { assignItemToTaxonomy } from "./command/assignItemToTaxonomy.generated";
import { removeItemFromTaxonomy } from "./command/removeItemFromTaxonomy.generated";
import { getItem } from "./query/getItem.generated";
import { getTaxonomyNode } from "./query/getTaxonomyNode.generated";
import { getTaxonomyNodeChildren } from "./query/getTaxonomyNodeChildren.generated";
import { getItemTaxonomyAssignment } from "./query/getItemTaxonomyAssignment.generated";
import { getTaxonomyNodeAssignments } from "./query/getTaxonomyNodeAssignments.generated";
import { calculateNodeDepth } from "./query/calculateNodeDepth.generated";
import { calculateSubtreeDepth } from "./query/calculateSubtreeDepth.generated";
import { detectCircularReference } from "./query/detectCircularReference.generated";
import { createItemType, type CreateItemTypeParams } from "./db/item";
import { createTaxonomyNodeType, type CreateTaxonomyNodeTypeParams } from "./db/taxonomyNode";
import {
  createItemTaxonomyAssignmentType,
  type CreateItemTaxonomyAssignmentTypeParams,
} from "./db/itemTaxonomyAssignment";
import { type EmptyFields, type FieldsToInsertable } from "@tailor-platform/erp-kit/module";

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

const DEFAULT_MAX_DEPTH = 10;

export interface DefineModuleParams<
  IF extends Record<string, TailorAnyDBField>,
  TNF extends Record<string, TailorAnyDBField>,
  ITAF extends Record<string, TailorAnyDBField>,
> {
  item?: CreateItemTypeParams<IF>;
  taxonomyNode?: CreateTaxonomyNodeTypeParams<TNF>;
  itemTaxonomyAssignment?: CreateItemTaxonomyAssignmentTypeParams<ITAF>;
  taxonomy?: { maxDepth?: number };
  primitives: {
    db: { unit: PrimitivesDB["unit"] };
    queries: { getUnit: PrimitivesQueries["getUnit"] };
  };
}

/* @__NO_SIDE_EFFECTS__ */
export const defineModule = <
  const IF extends Record<string, TailorAnyDBField> = EmptyFields,
  const TNF extends Record<string, TailorAnyDBField> = EmptyFields,
  const ITAF extends Record<string, TailorAnyDBField> = EmptyFields,
>(
  params: DefineModuleParams<IF, TNF, ITAF>,
) => {
  const item = createItemType({
    ...params.item,
    unitType: params.primitives.db.unit,
  });
  const taxonomyNode = createTaxonomyNodeType(params.taxonomyNode ?? {});
  const itemTaxonomyAssignment = createItemTaxonomyAssignmentType(
    params.itemTaxonomyAssignment ?? {},
  );

  const maxDepth = params.taxonomy?.maxDepth ?? DEFAULT_MAX_DEPTH;

  return {
    db: { item, taxonomyNode, itemTaxonomyAssignment },
    queries: {
      getItem,
      getTaxonomyNode,
      getTaxonomyNodeChildren,
      getItemTaxonomyAssignment,
      getTaxonomyNodeAssignments,
      calculateNodeDepth,
      calculateSubtreeDepth,
      detectCircularReference,
    },
    commands: {
      createItem: createItem<FieldsToInsertable<IF>>(params.primitives.queries),
      updateItem: updateItem<FieldsToInsertable<IF>>(params.primitives.queries),
      activateItem: activateItem(),
      deactivateItem: deactivateItem(),
      reactivateItem: reactivateItem(),
      deleteItem: deleteItem(),
      createTaxonomyNode: createTaxonomyNode<FieldsToInsertable<TNF>>({ maxDepth }),
      updateTaxonomyNode: updateTaxonomyNode<FieldsToInsertable<TNF>>(),
      moveTaxonomyNode: moveTaxonomyNode({ maxDepth }),
      deleteTaxonomyNode: deleteTaxonomyNode(),
      assignItemToTaxonomy: assignItemToTaxonomy(),
      removeItemFromTaxonomy: removeItemFromTaxonomy(),
    },
  };
};
