import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core";
import { approvalRequestLifecycle } from "../db/approvalRequest.lifecycle.generated";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  InvalidStatusTransitionError,
  MissingRequiredFieldError,
  RequestNotFoundError,
} from "../lib/errors.generated";

export interface CancelApprovalRequestInput {
  approvalRequestId: string;
  reason: string;
}

export async function run(db: Transaction, input: CancelApprovalRequestInput, ctx: CommandContext) {
  const request = await db
    .selectFrom("ApprovalRequest")
    .selectAll()
    .where("id", "=", input.approvalRequestId)
    .forUpdate()
    .executeTakeFirst();
  if (!request) return err(new RequestNotFoundError(input.approvalRequestId));

  const nextStatus = approvalRequestLifecycle.tryTransition(request.status, "cancel");
  if (!nextStatus) return err(new InvalidStatusTransitionError(input.approvalRequestId));

  if (input.reason.trim() === "") {
    return err(new MissingRequiredFieldError("reason"));
  }

  const now = new Date();
  await db
    .insertInto("ApprovalDecision")
    .values({
      approvalRequestId: request.id,
      decision: "CANCEL",
      decidedByUserId: ctx.actorId,
      comment: input.reason,
      decidedAt: now,
    })
    .execute();

  const updated = await db
    .updateTable("ApprovalRequest")
    .set({ status: nextStatus, resolvedAt: now })
    .where("id", "=", input.approvalRequestId)
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ approvalRequest: updated });
}
