import {
  type CommonReservedFields,
  type NoReservedFields,
  defaultGqlPermission,
  defaultPermission,
} from "@tailor-platform/erp-kit/core";
import { db, type TailorAnyDBField, type TailorAnyDBType } from "@tailor-platform/sdk";
import { accountPayableDocument } from "./accountPayableDocument";

export const ACCOUNT_PAYABLE_LINE_SOURCE_TYPES = ["PURCHASE_ORDER"] as const;
export const ACCOUNT_PAYABLE_LINE_CORRECTION_TYPES = ["PRICE", "QUANTITY", "AMOUNT"] as const;

const builtins = (params: {
  purchaseOrderLineType?: TailorAnyDBType;
  unitType?: TailorAnyDBType;
}) => {
  const unitId = db
    .uuid({ optional: true })
    .description("Supplier invoice unit of measure; required only for PURCHASE_ORDER source lines");
  const purchaseOrderLineId = db
    .uuid({ optional: true })
    .description("Foreign key to PurchaseOrderLine when sourceType is PURCHASE_ORDER");
  return {
    accountPayableDocumentId: db
      .uuid()
      .relation({
        type: "n-1",
        toward: { type: accountPayableDocument },
        backward: "lines",
      })
      .description("Foreign key to AccountPayableDocument"),
    netAmount: db.decimal().description("Positive line amount excluding tax"),
    taxAmount: db.decimal({ optional: true }).description("Optional tax amount"),
    grossAmount: db.decimal().description("Positive line amount including tax"),
    correctionOfLineId: db
      .uuid({ optional: true })
      .relation({
        type: "n-1",
        toward: { type: "self" },
        backward: "correctionLines",
      })
      .description("Optional self-reference to the posted AP document line being corrected"),
    correctionType: db
      .enum(ACCOUNT_PAYABLE_LINE_CORRECTION_TYPES, { optional: true })
      .description("Optional correction type for line-level AP corrections"),
    quantity: db
      .decimal({ optional: true })
      .description("Supplier invoice quantity; required only for PURCHASE_ORDER source lines"),
    unitPrice: db
      .decimal({ optional: true })
      .description("Supplier invoice unit price; required only for PURCHASE_ORDER source lines"),
    unitId: params.unitType
      ? unitId.relation({
          type: "n-1",
          toward: { type: params.unitType },
          backward: "accountPayableDocumentLines",
        })
      : unitId,
    description: db.string({ optional: true }).description("Optional line description"),
    sourceType: db
      .enum(ACCOUNT_PAYABLE_LINE_SOURCE_TYPES, { optional: true })
      .description("Optional AP line source type; PURCHASE_ORDER means purchaseOrderLineId is set"),
    purchaseOrderLineId: params.purchaseOrderLineType
      ? purchaseOrderLineId.relation({
          type: "n-1",
          toward: { type: params.purchaseOrderLineType },
          backward: "accountPayableDocumentLines",
        })
      : purchaseOrderLineId,
  };
};

type ReservedFields = keyof ReturnType<typeof builtins> | CommonReservedFields;

export interface CreateAccountPayableDocumentLineTypeParams<
  F extends Record<string, TailorAnyDBField>,
> {
  fields?: NoReservedFields<F, ReservedFields>;
  purchaseOrderLineType?: TailorAnyDBType;
  unitType?: TailorAnyDBType;
}

export function createAccountPayableDocumentLineType<
  const F extends Record<string, TailorAnyDBField>,
>(params: CreateAccountPayableDocumentLineTypeParams<F>) {
  return db
    .type("AccountPayableDocumentLine", {
      ...builtins(params),
      ...((params.fields ?? {}) as F),
      ...db.fields.timestamps(),
    })
    .permission(defaultPermission)
    .gqlPermission(defaultGqlPermission);
}

export const accountPayableDocumentLine = createAccountPayableDocumentLineType({});
