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

export interface ConsumeCommitmentInput {
  costElementId: string;
  costObjectType: string;
  costObjectId: string;
  accountingPeriodId: string;
  consumptionAmount: number;
}

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

  // Find commitment by cost element + cost object + period
  const commitment = await db
    .selectFrom("Commitment")
    .where("costElementId", "=", input.costElementId)
    .where("costObjectType", "=", input.costObjectType)
    .where("costObjectId", "=", input.costObjectId)
    .where("accountingPeriodId", "=", input.accountingPeriodId)
    .selectAll()
    .forUpdate()
    .executeTakeFirst();

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

  // Validate positive consumption amount
  if (input.consumptionAmount <= 0) {
    return err(new InvalidConsumptionAmountError(String(input.consumptionAmount)));
  }

  // Validate consumption does not exceed remaining
  const remaining = commitment.amount - commitment.consumedAmount;
  if (input.consumptionAmount > remaining) {
    return err(new ConsumptionExceedsCommitmentError(String(input.consumptionAmount)));
  }

  // Update consumedAmount; if fully consumed, set status to CONSUMED
  const newConsumedAmount = commitment.consumedAmount + input.consumptionAmount;
  const newStatus = newConsumedAmount >= commitment.amount ? "CONSUMED" : commitment.status;

  const updated = await db
    .updateTable("Commitment")
    .set({
      consumedAmount: newConsumedAmount,
      status: newStatus,
      updatedAt: new Date(),
    })
    .where("id", "=", commitment.id)
    .returningAll()
    .executeTakeFirst();

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