import {
  type CommonReservedFields,
  type NoReservedFields,
  defaultGqlPermission,
  defaultPermission,
} from "@tailor-platform/erp-kit/core";
import { db, type TailorAnyDBField, type TailorAnyDBType } from "@tailor-platform/sdk";
import { channel } from "./channel";
import { channelOrderLifecycle } from "./channelOrder.lifecycle.generated";
import { salesOrder } from "./salesOrder";
import { syncJob } from "./syncJob";

const builtins = (params: {
  companyType?: TailorAnyDBType;
  customerType?: TailorAnyDBType;
  currencyType?: TailorAnyDBType;
}) => {
  const companyId = db.uuid().description("Foreign key to Company");
  const customerId = db.uuid({ optional: true }).description("Optional mapped customer");
  const currencyId = db.uuid({ optional: true }).description("Optional mapped currency");
  return {
    companyId: params.companyType
      ? companyId.relation({
          type: "n-1",
          toward: { type: params.companyType },
          backward: "channelOrders",
        })
      : companyId,
    channelId: db
      .uuid()
      .relation({
        type: "n-1",
        toward: { type: channel },
        backward: "channelOrders",
      })
      .description("Foreign key to Channel"),
    externalOrderId: db.string().description("External order identifier"),
    externalCustomerId: db.string({ optional: true }).description("External buyer identifier"),
    customerId: params.customerType
      ? customerId.relation({
          type: "n-1",
          toward: { type: params.customerType },
          backward: "channelOrders",
        })
      : customerId,
    salesOrderId: db
      .uuid({ optional: true })
      .relation({
        type: "n-1",
        toward: { type: salesOrder },
        backward: "channelOrders",
      })
      .description("Optional linked SalesOrder"),
    status: db.enum(channelOrderLifecycle.states).description("Channel-order lifecycle status"),
    orderDate: db.date({ optional: true }).description("Channel order date"),
    currencyId: params.currencyType
      ? currencyId.relation({
          type: "n-1",
          toward: { type: params.currencyType },
          backward: "channelOrders",
        })
      : currencyId,
    rawPayload: db.string({ optional: true }).description("Serialized raw inbound payload"),
    normalizedPayload: db
      .string({ optional: true })
      .description("Serialized normalized channel-order payload"),
    errorSummary: db.string({ optional: true }).description("Latest exception summary"),
    retryContext: db.string({ optional: true }).description("Serialized retry context"),
    syncJobId: db
      .uuid({ optional: true })
      .relation({
        type: "n-1",
        toward: { type: syncJob },
        backward: "channelOrders",
      })
      .description("Optional originating SyncJob"),
  };
};

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

export interface CreateChannelOrderTypeParams<F extends Record<string, TailorAnyDBField>> {
  fields?: NoReservedFields<F, ReservedFields>;
  companyType?: TailorAnyDBType;
  customerType?: TailorAnyDBType;
  currencyType?: TailorAnyDBType;
}

export function createChannelOrderType<const F extends Record<string, TailorAnyDBField>>(
  params: CreateChannelOrderTypeParams<F>,
) {
  return db
    .type("ChannelOrder", {
      ...builtins(params),
      ...((params.fields ?? {}) as F),
      ...db.fields.timestamps(),
    })
    .indexes({
      fields: ["companyId", "channelId", "externalOrderId"],
      unique: true,
      name: "channel_order_company_channel_external_idx",
    })
    .permission(defaultPermission)
    .gqlPermission(defaultGqlPermission);
}

export const channelOrder = createChannelOrderType({});
