import type { Transaction } from "../generated/kysely-tailordb";
import {
  AllocationCycleNotFoundError,
  InvalidStateError,
  SenderNotFoundError,
  ReceiverNotFoundError,
  SenderIsReceiverError,
  InvalidPercentageError,
} from "../lib/errors.generated";
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";

export interface CreateAllocationRuleInput {
  allocationCycleId: string;
  senderCostCenterId: string;
  receiverType: string;
  receiverId: string;
  percentage: number;
}

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

  // Validate allocation cycle exists
  const cycle = await db
    .selectFrom("AllocationCycle")
    .where("id", "=", input.allocationCycleId)
    .selectAll()
    .forUpdate()
    .executeTakeFirst();

  if (!cycle) {
    return err(new AllocationCycleNotFoundError(input.allocationCycleId));
  }

  // Validate status is DRAFT
  if (cycle.status !== "DRAFT") {
    return err(new InvalidStateError(input.allocationCycleId));
  }

  // Validate sender cost center exists
  const sender = await db
    .selectFrom("CostCenter")
    .where("id", "=", input.senderCostCenterId)
    .selectAll()
    .executeTakeFirst();

  if (!sender) {
    return err(new SenderNotFoundError(input.senderCostCenterId));
  }

  // Validate receiver exists (polymorphic lookup)
  let receiver: unknown;
  if (input.receiverType === "CostCenter") {
    receiver = await db
      .selectFrom("CostCenter")
      .where("id", "=", input.receiverId)
      .selectAll()
      .executeTakeFirst();
  } else if (input.receiverType === "ProfitCenter") {
    receiver = await db
      .selectFrom("ProfitCenter")
      .where("id", "=", input.receiverId)
      .selectAll()
      .executeTakeFirst();
  } else if (input.receiverType === "InternalOrder") {
    receiver = await db
      .selectFrom("InternalOrder")
      .where("id", "=", input.receiverId)
      .selectAll()
      .executeTakeFirst();
  }

  if (!receiver) {
    return err(new ReceiverNotFoundError(input.receiverId));
  }

  // Validate sender is not receiver
  if (input.receiverType === "CostCenter" && input.senderCostCenterId === input.receiverId) {
    return err(new SenderIsReceiverError(input.senderCostCenterId));
  }

  // Validate percentage is positive
  if (input.percentage <= 0) {
    return err(new InvalidPercentageError(input.allocationCycleId));
  }

  // Create allocation rule
  const allocationRule = await db
    .insertInto("AllocationRule")
    .values({
      allocationCycleId: input.allocationCycleId,
      senderCostCenterId: input.senderCostCenterId,
      receiverType: input.receiverType,
      receiverId: input.receiverId,
      percentage: input.percentage,
      createdAt: new Date(),
      updatedAt: null,
    })
    .returningAll()
    .executeTakeFirst();

  return ok({ allocationRule: allocationRule! });
}
