import { db, type TailorAnyDBField, type TailorAnyDBType } from "@tailor-platform/sdk";
import { defaultGqlPermission, defaultPermission } from "../../../shared/modelPermissions";
import {
  businessPartner as businessPartnerStub,
  company as companyStub,
  site as siteStub,
} from "../lib/_db_deps";
import { purchaseOrderLifecycle } from "./purchaseOrder.lifecycle.generated";
import { purchasePaymentTerm } from "./purchasePaymentTerm";

export const RECEIPT_STATUSES = ["NOT_RECEIVED", "PARTIALLY_RECEIVED", "RECEIVED"] as const;

export const BILLING_STATUSES = ["NOT_BILLED", "PARTIALLY_BILLED", "BILLED"] as const;

/**
 * Fields stored in the `paymentTermSnapshotLines` JSON column.
 * Used both for the DB schema and for selecting snapshot-relevant
 * fields from PurchasePaymentTermLine.
 */
export const PAYMENT_TERM_SNAPSHOT_FIELDS = [
  "kind",
  "days",
  "fixedDayOfMonth",
  "percentage",
  "fixedAmount",
  "note",
] as const;

export interface CreatePurchaseOrderTypeParams<F extends Record<string, TailorAnyDBField>> {
  fields?: F;
  companyType: TailorAnyDBType;
  supplierType: TailorAnyDBType;
  siteType: TailorAnyDBType;
}

export function createPurchaseOrderType<const F extends Record<string, TailorAnyDBField>>(
  params: CreatePurchaseOrderTypeParams<F>,
) {
  return db
    .type("PurchaseOrder", {
      companyId: db
        .uuid()
        .relation({
          type: "n-1",
          toward: { type: params.companyType },
          backward: "purchaseOrders",
        })
        .description("Foreign key to Company"),
      supplierId: db
        .uuid()
        .relation({
          type: "n-1",
          toward: { type: params.supplierType },
          backward: "purchaseOrders",
        })
        .description("Foreign key to supplier BusinessPartner"),
      receivingSiteId: db
        .uuid({ optional: true })
        .relation({
          type: "n-1",
          toward: { type: params.siteType },
          backward: "purchaseOrders",
        })
        .description("Default receiving Site for the order"),
      paymentTermId: db
        .uuid()
        .relation({
          type: "n-1",
          toward: { type: purchasePaymentTerm },
          backward: "purchaseOrders",
        })
        .description("Selected PurchasePaymentTerm"),
      orderStatus: db
        .enum(purchaseOrderLifecycle.states)
        .description("Purchase-order lifecycle status"),
      receiptStatus: db
        .enum(RECEIPT_STATUSES, { optional: true })
        .description("Receipt fulfillment status — set on approval"),
      billingStatus: db
        .enum(BILLING_STATUSES, { optional: true })
        .description("Billing fulfillment status — set on approval"),
      orderDate: db.date().description("Purchase-order document date"),
      externalSupplierOrderReference: db
        .string({ optional: true })
        .description("Optional external supplier order reference"),
      supplierSnapshotName: db
        .string({ optional: true })
        .description("Snapshotted supplier display name at order time"),
      paymentTermSnapshotLines: db
        .object(
          {
            kind: db.string(),
            days: db.int({ optional: true }),
            fixedDayOfMonth: db.int({ optional: true }),
            percentage: db.decimal({ optional: true }),
            fixedAmount: db.decimal({ optional: true }),
            note: db.string({ optional: true }),
          },
          { array: true },
        )
        .description("Snapshotted payment-term schedule lines at snapshot time"),
      rejectionReason: db.string({ optional: true }).description("Latest rejection reason"),
      closeReason: db.string({ optional: true }).description("Close or write-off reason"),
      ...((params.fields ?? {}) as F),
      ...db.fields.timestamps(),
    })
    .permission(defaultPermission)
    .gqlPermission(defaultGqlPermission);
}

export const purchaseOrder = createPurchaseOrderType({
  companyType: companyStub,
  supplierType: businessPartnerStub,
  siteType: siteStub,
});
