import { ok, err } from "@tailor-platform/erp-kit/core";
import { Transaction, type Updateable } from "../generated/kysely-tailordb";
import { MissingRequiredFieldsError, NodeNotFoundError } from "../lib/errors.generated";

export type UpdateTaxonomyNodeInput = (
  | {
      id: string;
    }
  | {
      code: string;
    }
) & {
  name?: string;
};

/**
 * Function: updateTaxonomyNode
 *
 * Updates the display name of an existing taxonomy node.
 * The node can be looked up by id or code.
 */
export async function run<CF extends Record<string, unknown>>(
  db: Transaction,
  input: UpdateTaxonomyNodeInput & Omit<Partial<CF>, "status">,
) {
  const { name } = input;

  const KNOWN_KEYS = new Set(["id", "code", "name"]);
  const customFields: Record<string, unknown> = {};
  for (const [key, value] of Object.entries(input as Record<string, unknown>)) {
    if (!KNOWN_KEYS.has(key)) {
      customFields[key] = value;
    }
  }

  // 1. Check node exists (lookup by id or code)
  const node =
    "id" in input
      ? await db
          .selectFrom("TaxonomyNode")
          .selectAll()
          .where("id", "=", (input as { id: string }).id)
          .forUpdate()
          .executeTakeFirst()
      : await db
          .selectFrom("TaxonomyNode")
          .selectAll()
          .where("code", "=", (input as { code: string }).code)
          .forUpdate()
          .executeTakeFirst();

  if (!node) {
    const key = "id" in input ? (input as { id: string }).id : (input as { code: string }).code;
    return err(new NodeNotFoundError(key));
  }

  // 2. Name must be provided and non-empty (unless custom fields provided)
  const hasCustomFields = Object.keys(customFields).length > 0;
  if (!name && !hasCustomFields) {
    return err(new MissingRequiredFieldsError("name"));
  }

  // 3. Update fields
  const updates: Updateable<"TaxonomyNode"> = {
    ...(customFields as Updateable<"TaxonomyNode">),
  };
  if (name !== undefined) updates.name = name;

  const updatedNode = await db
    .updateTable("TaxonomyNode")
    .set(updates)
    .where("id", "=", node.id)
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ taxonomyNode: updatedNode });
}
