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

const builtins = (params: { userType?: TailorAnyDBType }) => {
  const createdByUserId = db
    .uuid()
    .description(
      "Foreign key to the User who created the pipeline. Immutable creation-time audit metadata; " +
        "ownership/responsibility semantics are a consumer concern (add via extension fields if needed).",
    );
  return {
    name: db.string().description("Pipeline name"),
    description: db
      .string({ optional: true })
      .description("Supplementary description or operational notes for the pipeline"),
    pipelineType: db
      .string()
      .description(
        "Pipeline kind. A free-form identifier defined by the consuming module/app (e.g. 'TASK_BOARD', 'SUPPORT_QUEUE'). " +
          "The set of allowed values can be injected via the pipelineTypes parameter of defineModule.",
      ),
    createdByUserId: params.userType
      ? createdByUserId.relation({
          type: "n-1",
          toward: { type: params.userType },
          backward: "createdPipelines",
        })
      : createdByUserId,
    status: db
      .enum(pipelineLifecycle.states)
      .description("ACTIVE = in operation / ARCHIVED = archived"),
    locked: db
      .bool()
      .description(
        "When true, the stage configuration (lanes) is fixed to the template used at creation time and stage-mutating commands are rejected. " +
          "It also skips the name uniqueness constraint (for managed boards whose identity is owned by the consuming module).",
      ),
    itemNumberSeq: db
      .int({ optional: true })
      .description(
        "The last itemNumber issued for this pipeline. A monotonically increasing counter. " +
          "Used instead of MAX(PipelineItem.itemNumber) to prevent number reuse after deletions.",
      ),
  };
};

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

export interface CreatePipelineTypeParams<F extends Record<string, TailorAnyDBField>> {
  fields?: NoReservedFields<F, ReservedFields>;
  /** Related User type (user-management module). The instance wired by the consuming app is injected here. */
  userType?: TailorAnyDBType;
}

export function createPipelineType<const F extends Record<string, TailorAnyDBField>>(
  params: CreatePipelineTypeParams<F>,
) {
  return db
    .type("Pipeline", {
      ...builtins(params),
      // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- mirrors erp-kit's createXxxType factories; field bag is constrained but TS can't prove F is concrete
      ...((params.fields ?? {}) as F),
      ...db.fields.timestamps(),
    })
    .description(
      "Pipeline. A kanban board unit that manages items. Multiple pipelines can be created per app; scoping (company, project, etc.) is a consumer concern expressed via extension fields.",
    )
    .permission(defaultPermission)
    .gqlPermission(defaultGqlPermission);
}

export const pipeline = createPipelineType({});
