import type { Transaction } from "../generated/kysely-tailordb";
import { ProfitCenterNotFoundError, HierarchyNodeNotFoundError } from "../lib/errors.generated";
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";

export interface AssignProfitCenterToHierarchyNodeInput {
  profitCenterId: string;
  hierarchyNodeId: string;
}

export async function run(
  db: Transaction,
  input: AssignProfitCenterToHierarchyNodeInput,
  ctx: CommandContext,
) {
  void ctx;

  // Validate profit center exists
  const profitCenter = await db
    .selectFrom("ProfitCenter")
    .selectAll()
    .where("id", "=", input.profitCenterId)
    .forUpdate()
    .executeTakeFirst();

  if (!profitCenter) {
    return err(new ProfitCenterNotFoundError(input.profitCenterId));
  }

  // Validate target hierarchy node exists
  const node = await db
    .selectFrom("ProfitCenterHierarchyNode")
    .selectAll()
    .where("id", "=", input.hierarchyNodeId)
    .executeTakeFirst();

  if (!node) {
    return err(new HierarchyNodeNotFoundError(input.hierarchyNodeId));
  }

  const hierarchyId = node.hierarchyId;

  // Check if an assignment already exists for this profit center in this hierarchy
  const existingAssignment = await db
    .selectFrom("ProfitCenterHierarchyAssignment")
    .selectAll()
    .where("profitCenterId", "=", input.profitCenterId)
    .where("hierarchyId", "=", hierarchyId)
    .forUpdate()
    .executeTakeFirst();

  const assignment = existingAssignment
    ? await db
        .updateTable("ProfitCenterHierarchyAssignment")
        .set({ hierarchyNodeId: input.hierarchyNodeId, updatedAt: new Date() })
        .where("id", "=", existingAssignment.id)
        .returningAll()
        .executeTakeFirstOrThrow()
    : await db
        .insertInto("ProfitCenterHierarchyAssignment")
        .values({
          profitCenterId: input.profitCenterId,
          hierarchyId,
          hierarchyNodeId: input.hierarchyNodeId,
          createdAt: new Date(),
          updatedAt: null,
        })
        .returningAll()
        .executeTakeFirstOrThrow();

  return ok({ profitCenterHierarchyAssignment: assignment });
}
