import { Transaction } from "../generated/kysely-tailordb";
import {
  DuplicateAssignmentError,
  ItemNotFoundError,
  NodeNotFoundError,
} from "../lib/errors.generated";
import { ok, err } from "@tailor-platform/erp-kit/module";

export interface AssignItemToTaxonomyInput {
  itemId: string;
  taxonomyNodeId: string;
}

/**
 * Function: assignItemToTaxonomy
 *
 * Creates a link between an item and a taxonomy node for many-to-many classification.
 */
export async function run(db: Transaction, input: AssignItemToTaxonomyInput) {
  const { itemId, taxonomyNodeId } = input;

  // 1. Check item exists (validation only — not writing to Item)
  const item = await db.selectFrom("Item").selectAll().where("id", "=", itemId).executeTakeFirst();

  if (!item) {
    return err(new ItemNotFoundError(itemId));
  }

  // 2. Check node exists (validation only — not writing to TaxonomyNode)
  const node = await db
    .selectFrom("TaxonomyNode")
    .selectAll()
    .where("id", "=", taxonomyNodeId)
    .executeTakeFirst();

  if (!node) {
    return err(new NodeNotFoundError(taxonomyNodeId));
  }

  // 3. Check for duplicate assignment (uniqueness before insert — lock)
  const existing = await db
    .selectFrom("ItemTaxonomyAssignment")
    .selectAll()
    .where("itemId", "=", itemId)
    .where("taxonomyNodeId", "=", taxonomyNodeId)
    .forUpdate()
    .executeTakeFirst();

  if (existing) {
    return err(new DuplicateAssignmentError(`${itemId} in ${taxonomyNodeId}`));
  }

  // 4. Create assignment
  const assignment = await db
    .insertInto("ItemTaxonomyAssignment")
    .values({
      itemId,
      taxonomyNodeId,
      createdAt: new Date(),
      updatedAt: null,
    })
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ assignment: assignment });
}
