import { db, type TailorAnyDBField, type TailorAnyDBType } from "@tailor-platform/sdk";
import { defaultGqlPermission, defaultPermission } from "../../../shared/modelPermissions";
import { item as itemStub, site as siteStub } from "../lib/_db_deps";
import { inventorySupplyPlanLifecycle } from "./inventorySupplyPlan.lifecycle.generated";
import { lot } from "./lot";
import { serialNumber } from "./serialNumber";

export const SUPPLY_PLAN_SOURCE_TYPES = [
  "PURCHASE_ORDER",
  "TRANSFER_ORDER",
  "MANUFACTURING_ORDER",
] as const;

export interface CreateInventorySupplyPlanTypeParams<F extends Record<string, TailorAnyDBField>> {
  fields?: F;
  itemType: TailorAnyDBType;
  siteType: TailorAnyDBType;
}

export function createInventorySupplyPlanType<const F extends Record<string, TailorAnyDBField>>(
  params: CreateInventorySupplyPlanTypeParams<F>,
) {
  return db
    .type("InventorySupplyPlan", {
      sourceType: db
        .enum(SUPPLY_PLAN_SOURCE_TYPES)
        .description("Source document type: PURCHASE_ORDER, TRANSFER_ORDER, MANUFACTURING_ORDER"),
      sourceId: db
        .uuid()
        .description(
          "ID of the source document (e.g., PurchaseOrder.id). Generic reference; not a typed foreign key.",
        ),
      sourceLineId: db
        .uuid()
        .description(
          "ID of the source supply line (e.g., PurchaseOrderLine.id). In the standard modules this is the unique source unit for one supply projection.",
        ),
      itemId: db
        .uuid()
        .relation({
          type: "n-1",
          toward: { type: params.itemType },
        })
        .description("Foreign key to Item"),
      siteId: db
        .uuid()
        .relation({
          type: "n-1",
          toward: { type: params.siteType },
        })
        .description("Destination site for the expected supply"),
      expectedQuantity: db
        .decimal()
        .description("Committed expected quantity for this ATP supply slice"),
      receivedQuantity: db
        .decimal()
        .description(
          "Cumulative quantity already received against this source line; open quantity is derived as expectedQuantity minus receivedQuantity",
        ),
      status: db
        .enum(inventorySupplyPlanLifecycle.states)
        .description(
          "Projection lifecycle status: OPEN while expected supply remains, CLOSED when it no longer contributes open supply",
        ),
      expectedDate: db.date().description("Latest expected receipt date from the source line"),
      lotId: db
        .uuid({ optional: true })
        .relation({
          type: "n-1",
          toward: { type: lot },
        })
        .description("Optional foreign key to Lot for lot-tracked items"),
      serialNumberId: db
        .uuid({ optional: true })
        .relation({
          type: "n-1",
          toward: { type: serialNumber },
        })
        .description("Optional foreign key to SerialNumber for serial-tracked items"),
      ...((params.fields ?? {}) as F),
      ...db.fields.timestamps(),
    })
    .indexes(
      {
        fields: ["sourceType", "sourceLineId"],
        unique: true,
        name: "inventory_supply_plan_source_idx",
      },
      {
        fields: ["sourceType", "sourceId"],
        unique: false,
        name: "inventory_supply_plan_source_document_idx",
      },
    )
    .permission(defaultPermission)
    .gqlPermission(defaultGqlPermission);
}

export const inventorySupplyPlan = createInventorySupplyPlanType({
  itemType: itemStub,
  siteType: siteStub,
});
