import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core";
import { pipelineItemLifecycle } from "../db/pipelineItem.lifecycle.generated";
import type { Transaction } from "../generated/kysely-tailordb";
import { ItemNotFoundError, ItemNotOpenError } from "../lib/errors.generated";

export interface ClosePipelineItemInput {
  itemId: string;
}

export async function run(db: Transaction, input: ClosePipelineItemInput, ctx: CommandContext) {
  const item = await db
    .selectFrom("PipelineItem")
    .selectAll()
    .where("id", "=", input.itemId)
    .forUpdate()
    .executeTakeFirst();

  if (!item) {
    return err(new ItemNotFoundError(input.itemId));
  }

  const nextLifecycle = pipelineItemLifecycle.tryTransition(item.lifecycle, "close");
  if (!nextLifecycle) {
    return err(new ItemNotOpenError(input.itemId));
  }

  const now = new Date();

  const closedItem = await db
    .updateTable("PipelineItem")
    .set({
      lifecycle: nextLifecycle,
      updatedAt: now,
    })
    .where("id", "=", input.itemId)
    .returningAll()
    .executeTakeFirst();

  await db
    .insertInto("PipelineItemChange")
    .values({
      itemId: item.id,
      changedByUserId: ctx.actorId,
      changeType: "LIFECYCLE",
      fieldName: "LIFECYCLE",
      prevValue: item.lifecycle,
      newValue: nextLifecycle,
      createdAt: now,
      updatedAt: null,
    })
    .execute();

  return ok({
    item: closedItem ?? { ...item, lifecycle: nextLifecycle, updatedAt: now },
  });
}
