import { db, type TailorAnyDBField, type TailorAnyDBType } from "@tailor-platform/sdk";
import { defaultGqlPermission, defaultPermission } from "../../../shared/modelPermissions";
import { role as roleStub, user as userStub } from "../lib/_db_deps";
import { approvalStep } from "./approvalStep";
import { approvalStepAssigneeLifecycle } from "./approvalStepAssignee.lifecycle.generated";

const ROLE_QUORUM_TYPES = ["ALL", "ANY"] as const;

export interface CreateApprovalStepAssigneeTypeParams<F extends Record<string, TailorAnyDBField>> {
  fields?: F;
  userType: TailorAnyDBType;
  roleType: TailorAnyDBType;
}

export function createApprovalStepAssigneeType<const F extends Record<string, TailorAnyDBField>>(
  params: CreateApprovalStepAssigneeTypeParams<F>,
) {
  return db
    .type("ApprovalStepAssignee", {
      approvalStepId: db
        .uuid()
        .relation({
          type: "n-1",
          toward: { type: approvalStep },
          backward: "assignees",
        })
        .description("Foreign key to parent ApprovalStep"),
      userId: db
        .uuid({ optional: true })
        .relation({
          type: "n-1",
          toward: { type: params.userType },
          backward: "approvalStepAssignees",
        })
        .description("Concrete user voter; XOR with roleId before role expansion, set after"),
      roleId: db
        .uuid({ optional: true })
        .relation({
          type: "n-1",
          toward: { type: params.roleType },
          backward: "approvalStepAssignees",
        })
        .description(
          "Role placeholder; retained for traceability after expansion (XOR with userId before expansion)",
        ),
      required: db
        .bool()
        .description(
          "User-assignee mandatory flag (meaningful only when roleId is null after expansion, ignored on role-expanded rows)",
        ),
      roleQuorum: db
        .enum(ROLE_QUORUM_TYPES, { optional: true })
        .description(
          "Group semantics propagated from the originating role assignee (meaningful only when roleId is set): ALL = every group member must approve, ANY = any one suffices, null = no group-level constraint",
        ),
      status: db
        .enum(approvalStepAssigneeLifecycle.states)
        .description("Per-assignee voting status: PENDING, APPROVED, REJECTED, or DELEGATED"),
      resolvedAt: db
        .datetime({ optional: true })
        .description("Set when status reaches APPROVED, REJECTED, or DELEGATED"),
      ...((params.fields ?? {}) as F),
      ...db.fields.timestamps(),
    })
    .permission(defaultPermission)
    .gqlPermission(defaultGqlPermission);
}

export const approvalStepAssignee = createApprovalStepAssigneeType({
  userType: userStub,
  roleType: roleStub,
});
