import type { Transaction } from "../generated/kysely-tailordb";
import {
  WorkCenterNotFoundError,
  WorkCenterNotActivatableError,
  MissingCalendarContextError,
  InvalidCapacityError,
  InvalidRateError,
  OverheadCurrencyRequiredError,
} from "../lib/errors.generated";
import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/module";

const ACTIVATABLE_STATUSES = ["DRAFT", "INACTIVE"] as const;

export interface ActivateWorkCenterInput {
  id: string;
  from?: string[];
}

/**
 * Function: activateWorkCenter
 *
 * Validates that a draft or inactive work center has the execution data
 * required by planning and costing, then marks it available for routing
 * and work-order use.
 */
export async function run<CF extends Record<string, unknown>>(
  db: Transaction,
  input: ActivateWorkCenterInput & CF,
  _ctx: CommandContext,
) {
  const { id, from, ...customFields } = input;
  void customFields;

  const allowedStatuses = from ?? [...ACTIVATABLE_STATUSES];

  // 1. Fetch work center with lock
  const workCenter = await db
    .selectFrom("WorkCenter")
    .selectAll()
    .where("id", "=", id)
    .forUpdate()
    .executeTakeFirst();

  if (!workCenter) {
    return err(new WorkCenterNotFoundError(id));
  }

  // 2. Validate status is activatable
  if (!allowedStatuses.includes(workCenter.status)) {
    return err(new WorkCenterNotActivatableError(workCenter.code));
  }

  // 3. Validate calendar context
  if (!workCenter.calendarReference) {
    return err(new MissingCalendarContextError(workCenter.code));
  }

  // 4. Validate capacity > 0
  if (workCenter.capacityAssumptions <= 0) {
    return err(new InvalidCapacityError(workCenter.code));
  }

  // 5. Validate rates >= 0
  if (workCenter.laborRate != null && workCenter.laborRate < 0) {
    return err(new InvalidRateError(workCenter.code));
  }
  if (workCenter.machineRate != null && workCenter.machineRate < 0) {
    return err(new InvalidRateError(workCenter.code));
  }

  // 6. Validate overhead currency for FIXED_AMOUNT_PER_GOOD_UNIT
  if (
    workCenter.overheadAbsorptionMethod === "FIXED_AMOUNT_PER_GOOD_UNIT" &&
    !workCenter.overheadAbsorptionCurrency
  ) {
    return err(new OverheadCurrencyRequiredError(workCenter.code));
  }

  // 7. Set status to ACTIVE
  const updatedWorkCenter = await db
    .updateTable("WorkCenter")
    .set({
      status: "ACTIVE",
      updatedAt: new Date(),
    })
    .where("id", "=", id)
    .returningAll()
    .executeTakeFirst();

  return ok({ workCenter: updatedWorkCenter! });
}
