import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/core";
import { billOfMaterialLifecycle } from "../db/billOfMaterial.lifecycle.generated";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  BomNotFoundError,
  BomNotDeactivatableError,
  ReplacementRequiredError,
} from "../lib/errors.generated";

export interface DeactivateBillOfMaterialInput {
  id: string;
}

/**
 * Function: deactivateBillOfMaterial
 *
 * Removes an active BOM version from future selection. Preserves audit
 * history and any released production-order snapshots that already depend
 * on the version.
 */
export async function run(
  db: Transaction,
  input: DeactivateBillOfMaterialInput,
  _ctx: CommandContext,
) {
  const { id } = input;

  // 1. Fetch BOM with lock
  const bom = await db
    .selectFrom("BillOfMaterial")
    .selectAll()
    .where("id", "=", id)
    .forUpdate()
    .executeTakeFirst();

  if (!bom) {
    return err(new BomNotFoundError(id));
  }

  // 2. Validate status is deactivatable
  const nextStatus = billOfMaterialLifecycle.tryTransition(bom.status, "deactivate");
  if (!nextStatus) {
    return err(new BomNotDeactivatableError(id));
  }

  // 3. Check replacement policy — if this is the only active BOM for this
  //    parent item in scope and it is the default selection, a replacement
  //    active version must exist before deactivation
  if (bom.defaultSelection) {
    const replacementBom = await db
      .selectFrom("BillOfMaterial")
      .selectAll()
      .where("parentItemId", "=", bom.parentItemId)
      .where("companyId", "=", bom.companyId)
      .where("id", "!=", id)
      .where("status", "=", "ACTIVE")
      .executeTakeFirst();

    if (!replacementBom) {
      return err(new ReplacementRequiredError(id));
    }
  }

  // 4. Set status to INACTIVE
  const updatedBom = await db
    .updateTable("BillOfMaterial")
    .set({
      status: nextStatus,
    })
    .where("id", "=", id)
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ billOfMaterial: updatedBom });
}
