/* 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,
  PriceRuleNotFoundError,
  UnitNotFoundError,
} from "../lib/errors.generated";
import { findRuleConflict, isActiveStatus, selectOne } from "../lib/domain";
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";

export type UpdatePurchasePriceRuleInput = {
  id: string;
  itemId?: string;
  currencyId?: string;
  unitId?: string;
  minimumQuantity?: number;
  unitPrice?: number;
  effectiveFrom?: Date;
  effectiveTo?: Date | null;
  priority?: number;
  notes?: string | null;
};
export async function run(
  db: Transaction,
  input: UpdatePurchasePriceRuleInput,
  ctx: CommandContext,
) {
  const existing = await selectOne(db, "PurchasePriceRule", "id", input.id, true);
  if (!existing) {
    return err(new PriceRuleNotFoundError(input.id));
  }

  const itemId = input.itemId ?? (existing.itemId as string);
  const currencyId = input.currencyId ?? (existing.currencyId as string);
  const unitId = input.unitId ?? (existing.unitId as string);
  const minimumQuantity = input.minimumQuantity ?? (existing.minimumQuantity as number);
  const unitPrice = input.unitPrice ?? (existing.unitPrice as number);
  const effectiveFrom = input.effectiveFrom ?? (existing.effectiveFrom as Date);
  const effectiveTo =
    input.effectiveTo === undefined
      ? ((existing.effectiveTo as Date | null) ?? null)
      : input.effectiveTo;

  const item = await selectOne(db, "Item", "id", itemId);
  if (!item) {
    return err(new ItemNotFoundError(itemId));
  }
  if (!isActiveStatus(item.status as string | null)) {
    return err(new ItemNotActiveError(itemId));
  }
  if (!(await selectOne(db, "Currency", "id", currencyId))) {
    return err(new CurrencyNotFoundError(currencyId));
  }
  if (!(await selectOne(db, "Unit", "id", unitId))) {
    return err(new UnitNotFoundError(unitId));
  }
  if (unitPrice <= 0) {
    return err(new InvalidUnitPriceError(String(unitPrice)));
  }
  if (minimumQuantity < 0) {
    return err(new InvalidMinimumQuantityError(String(minimumQuantity)));
  }
  if (effectiveTo && effectiveTo < effectiveFrom) {
    return err(new InvalidEffectiveRangeError(input.id));
  }

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

  const purchasePriceRule = await db
    .updateTable("PurchasePriceRule")
    .set({
      itemId,
      currencyId,
      unitId,
      minimumQuantity,
      unitPrice,
      effectiveFrom,
      effectiveTo,
      priority: input.priority ?? existing.priority,
      notes: input.notes === undefined ? existing.notes : input.notes,
      updatedAt: new Date(),
    })
    .where("id", "=", input.id)
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ purchasePriceRule });
}
