import type { Transaction } from "../generated/kysely-tailordb";
import { CommitmentNotFoundError, NoCommitmentToReleaseError } from "../lib/errors.generated";
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";

export interface ReleaseCommitmentInput {
  costElementId: string;
  costObjectType: string;
  costObjectId: string;
  accountingPeriodId: string;
  purchaseOrderId: string;
}

export async function run(db: Transaction, input: ReleaseCommitmentInput, ctx: CommandContext) {
  void ctx;

  // Find commitment
  const commitment = await db
    .selectFrom("Commitment")
    .where("costElementId", "=", input.costElementId)
    .where("costObjectType", "=", input.costObjectType)
    .where("costObjectId", "=", input.costObjectId)
    .where("accountingPeriodId", "=", input.accountingPeriodId)
    .where("purchaseOrderId", "=", input.purchaseOrderId)
    .selectAll()
    .forUpdate()
    .executeTakeFirst();

  if (!commitment) {
    return err(new CommitmentNotFoundError(input.costElementId));
  }

  // Remaining amount must be > 0
  const remaining = commitment.amount - commitment.consumedAmount;
  if (remaining <= 0) {
    return err(new NoCommitmentToReleaseError(commitment.id));
  }

  // Set status to RELEASED and consumedAmount = amount (fully released)
  const updated = await db
    .updateTable("Commitment")
    .set({
      consumedAmount: commitment.amount,
      status: "RELEASED",
      updatedAt: new Date(),
    })
    .where("id", "=", commitment.id)
    .returningAll()
    .executeTakeFirst();

  return ok({ commitment: updated! });
}
