import { ok, err } from "@tailor-platform/erp-kit/core";
import { unitLifecycle } from "../db/unit.lifecycle.generated";
import { Transaction } from "../generated/kysely-tailordb";
import { CannotDeactivateReferenceUnitError, UnitNotFoundError } from "../lib/errors.generated";

export interface DeactivateUnitInput {
  unitId: string;
}

/**
 * Function: deactivateUnit
 *
 * Disables a unit of measure from being used in new product assignments
 * and quantity conversions while preserving all historical data.
 * Reference units cannot be deactivated.
 */
export async function run(db: Transaction, input: DeactivateUnitInput) {
  // 1. Find unit by ID
  const unit = await db
    .selectFrom("Unit")
    .selectAll()
    .where("id", "=", input.unitId)
    .forUpdate()
    .executeTakeFirst();

  // 2. If not found, throw error
  if (!unit) {
    return err(new UnitNotFoundError(input.unitId));
  }

  // 3. Check if unit is reference unit for its category
  const uoMCategory = await db
    .selectFrom("UoMCategory")
    .selectAll()
    .where("id", "=", unit.categoryId)
    .executeTakeFirst();

  if (uoMCategory?.referenceUnitId === unit.id) {
    return err(new CannotDeactivateReferenceUnitError(input.unitId));
  }

  // 4. If already inactive, return unit (idempotent)
  const nextStatus = unitLifecycle.tryTransition(unit.status, "deactivate");
  if (!nextStatus) {
    return ok({ unit });
  }

  // 5. Update status to INACTIVE
  const updatedUnit = await db
    .updateTable("Unit")
    .set({
      status: nextStatus,
    })
    .where("id", "=", input.unitId)
    .returningAll()
    .executeTakeFirstOrThrow();

  // 6. Return updated unit
  return ok({ unit: updatedUnit });
}
