/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unused-vars */
import type { Transaction } from "../generated/kysely-tailordb";
import {
  CurrencyNotFoundError,
  DuplicateRulePrecedenceError,
  InvalidEffectiveRangeError,
  InvalidMinimumQuantityError,
  InvalidUnitPriceError,
  ItemNotActiveError,
  ItemNotFoundError,
  PriceListNotFoundError,
  UnitNotFoundError,
} from "../lib/errors.generated";
import { findRuleConflict, isActiveStatus, selectOne } from "../lib/domain";
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";

export interface CreatePurchasePriceRuleInput {
  priceListId: string;
  itemId: string;
  currencyId: string;
  unitId: string;
  minimumQuantity: number;
  unitPrice: number;
  effectiveFrom: Date;
  effectiveTo?: Date | null;
  priority?: number;
  notes?: string;
}

export async function run(
  db: Transaction,
  input: CreatePurchasePriceRuleInput,
  ctx: CommandContext,
) {
  if (!(await selectOne(db, "PurchasePriceList", "id", input.priceListId))) {
    return err(new PriceListNotFoundError(input.priceListId));
  }

  const item = await selectOne(db, "Item", "id", input.itemId);
  if (!item) {
    return err(new ItemNotFoundError(input.itemId));
  }
  if (!isActiveStatus(item.status as string | null)) {
    return err(new ItemNotActiveError(input.itemId));
  }

  if (!(await selectOne(db, "Currency", "id", input.currencyId))) {
    return err(new CurrencyNotFoundError(input.currencyId));
  }
  if (!(await selectOne(db, "Unit", "id", input.unitId))) {
    return err(new UnitNotFoundError(input.unitId));
  }
  if (input.unitPrice <= 0) {
    return err(new InvalidUnitPriceError(String(input.unitPrice)));
  }
  if (input.minimumQuantity < 0) {
    return err(new InvalidMinimumQuantityError(String(input.minimumQuantity)));
  }
  if (input.effectiveTo && input.effectiveTo < input.effectiveFrom) {
    return err(new InvalidEffectiveRangeError(input.itemId));
  }

  const conflictingRule = await findRuleConflict(db, {
    itemId: input.itemId,
    currencyId: input.currencyId,
    unitId: input.unitId,
    minimumQuantity: input.minimumQuantity,
    effectiveFrom: input.effectiveFrom,
  });
  if (conflictingRule) {
    return err(new DuplicateRulePrecedenceError(input.itemId));
  }

  const purchasePriceRule = await db
    .insertInto("PurchasePriceRule")
    .values({
      priceListId: input.priceListId,
      itemId: input.itemId,
      currencyId: input.currencyId,
      unitId: input.unitId,
      minimumQuantity: input.minimumQuantity,
      unitPrice: input.unitPrice,
      effectiveFrom: input.effectiveFrom,
      effectiveTo: input.effectiveTo ?? null,
      priority: input.priority ?? 0,
      status: "ACTIVE",
      notes: input.notes ?? null,
      createdAt: new Date(),
      updatedAt: null,
    })
    .returningAll()
    .executeTakeFirst();

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