import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core";
import { channelOrderLifecycle } from "../db/channelOrder.lifecycle.generated";
import type { Transaction } from "../generated/kysely-tailordb";
import { encodeJson } from "../lib/domain";
import {
  ChannelOrderNotFoundError,
  ExceptionContextRequiredError,
  InvalidChannelOrderStatusError,
} from "../lib/errors.generated";

export interface MarkChannelOrderExceptionInput {
  channelOrderId: string;
  errorSummary?: string;
  retryContext?: Record<string, unknown> | null;
}

export async function run(
  db: Transaction,
  input: MarkChannelOrderExceptionInput,
  ctx: CommandContext,
) {
  void ctx;
  const channelOrder = await db
    .selectFrom("ChannelOrder")
    .selectAll()
    .where("id", "=", input.channelOrderId)
    .forUpdate()
    .executeTakeFirst();
  if (!channelOrder) {
    return err(new ChannelOrderNotFoundError(input.channelOrderId));
  }
  const nextStatus = channelOrderLifecycle.tryTransition(channelOrder.status, "markException");
  if (!nextStatus) {
    return err(new InvalidChannelOrderStatusError(input.channelOrderId));
  }
  if (!input.errorSummary && !input.retryContext) {
    return err(new ExceptionContextRequiredError(input.channelOrderId));
  }
  const updated = await db
    .updateTable("ChannelOrder")
    .set({
      status: nextStatus,
      errorSummary: input.errorSummary ?? channelOrder.errorSummary,
      retryContext: input.retryContext ? encodeJson(input.retryContext) : channelOrder.retryContext,
    })
    .where("id", "=", input.channelOrderId)
    .returningAll()
    .executeTakeFirstOrThrow();
  return ok({ channelOrder: updated });
}
