import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core";
import type { Transaction } from "../generated/kysely-tailordb";
import { CommentNotFoundError, ForbiddenError, InvalidBodyError } from "../lib/errors.generated";

export interface UpdatePipelineItemCommentInput {
  commentId: string;
  body: string;
}

const COMMENT_OWN_KEYS = new Set(["commentId", "body"]);

// Module-managed PipelineItemComment columns that must never be writable through
// the extension-field pass-through — authorUserId backs the author-only check.
const COMMENT_RESERVED_KEYS = new Set(["id", "itemId", "authorUserId", "createdAt", "updatedAt"]);

export async function run<CF extends Record<string, unknown>>(
  db: Transaction,
  input: UpdatePipelineItemCommentInput & Partial<CF>,
  ctx: CommandContext,
) {
  // Consumer extension fields (declared via defineModule's pipelineItemComment.fields)
  // pass through to the update untouched — except reserved model columns.
  const customFields: Record<string, unknown> = {};
  for (const [key, value] of Object.entries(input as Record<string, unknown>)) {
    if (!COMMENT_OWN_KEYS.has(key) && !COMMENT_RESERVED_KEYS.has(key)) {
      customFields[key] = value;
    }
  }

  const comment = await db
    .selectFrom("PipelineItemComment")
    .selectAll()
    .where("id", "=", input.commentId)
    .forUpdate()
    .executeTakeFirst();

  if (!comment) {
    return err(new CommentNotFoundError(input.commentId));
  }

  if (comment.authorUserId !== ctx.actorId) {
    return err(new ForbiddenError(input.commentId));
  }

  if (!input.body.trim()) {
    return err(new InvalidBodyError(input.commentId));
  }

  const update: Record<string, unknown> = {
    ...customFields,
    body: input.body,
    updatedAt: new Date(),
  };

  const updatedComment = await db
    .updateTable("PipelineItemComment")
    .set(update)
    .where("id", "=", input.commentId)
    .returningAll()
    .executeTakeFirst();

  return ok({ comment: updatedComment ?? { ...comment, ...update } });
}
