import { ok, type ReadonlyDB, type QueryContext } from "@tailor-platform/erp-kit/core";
import { Decimal } from "decimal.js";
import type { DB } from "../generated/kysely-tailordb";

function effectiveDateInRange(date: Date, from: Date, to?: Date | null) {
  if (date < from) return false;
  if (to && date > to) return false;
  return true;
}

export interface CalculatePurchasePriceInput {
  companyId: string;
  supplierId: string;
  itemId: string;
  unitId: string;
  currencyId: string;
  quantity: string;
  pricingDate?: Date;
}

export async function run(
  db: ReadonlyDB<DB>,
  input: CalculatePurchasePriceInput,
  ctx: QueryContext,
) {
  void ctx;

  const rules = await db
    .selectFrom("PurchasePriceRule")
    .selectAll()
    .where("itemId", "=", input.itemId)
    .execute();
  const lists = await db
    .selectFrom("PurchasePriceList")
    .selectAll()
    .where("companyId", "=", input.companyId)
    .where("supplierId", "=", input.supplierId)
    .execute();

  const activeLists = lists.filter((list) => list.status === "ACTIVE");
  const activeListIds = new Set(activeLists.map((list) => list.id));
  const listPriorityMap = new Map(activeLists.map((list) => [list.id, list.priority]));
  const pricingDate = input.pricingDate ?? new Date();

  const matchingRules = rules
    .filter((rule) => rule.status === "ACTIVE")
    .filter((rule) => activeListIds.has(rule.priceListId))
    .filter((rule) => rule.currencyId === input.currencyId)
    .filter((rule) => rule.unitId === input.unitId)
    .filter((rule) => new Decimal(input.quantity).gte(rule.minimumQuantity))
    .filter((rule) => effectiveDateInRange(pricingDate, rule.effectiveFrom, rule.effectiveTo))
    .sort((left, right) => {
      const listPriorityCmp =
        (listPriorityMap.get(right.priceListId) ?? 0) -
        (listPriorityMap.get(left.priceListId) ?? 0);
      if (listPriorityCmp !== 0) return listPriorityCmp;
      const cmp = new Decimal(right.minimumQuantity).cmp(left.minimumQuantity);
      if (cmp !== 0) return cmp;
      return right.priority - left.priority;
    });

  const matchedRule = matchingRules[0] ?? null;
  const priceSuggestion = matchedRule
    ? {
        ruleId: matchedRule.id,
        priceListId: matchedRule.priceListId,
        unitPrice: matchedRule.unitPrice,
      }
    : null;

  return ok({ priceSuggestion, matchedRule });
}
