/**
 * Calculation Rules Engine — matches absence days against rules
 * to determine cost and chargeability effects.
 *
 * Pure function — no DB imports.
 */

import type {
  AbsenceTrigger,
  CalculationRule,
  CostEffect,
  ChargeabilityEffect,
} from "@capakraken/shared";

export interface RuleMatch {
  rule: CalculationRule;
  costEffect: CostEffect;
  chargeabilityEffect: ChargeabilityEffect;
  costReductionPercent: number | null;
}

/**
 * Specificity score for a rule — more specific filters = higher score.
 */
function specificityScore(rule: CalculationRule): number {
  let score = 0;
  if (rule.projectId) score += 2;
  if (rule.orderType) score += 1;
  return score;
}

/**
 * Find the best matching rule for a given absence day.
 *
 * Matching:
 * 1. triggerType must match
 * 2. isActive must be true
 * 3. projectId must match (null = all projects)
 * 4. orderType must match (null = all order types)
 *
 * Ranking: highest specificity wins, then highest priority.
 */
export function findMatchingRule(
  rules: CalculationRule[],
  triggerType: AbsenceTrigger,
  projectId?: string | null,
  orderType?: string | null,
): RuleMatch | null {
  const candidates = rules.filter((r) => {
    if (!r.isActive) return false;
    if (r.triggerType !== triggerType) return false;
    if (r.projectId && r.projectId !== projectId) return false;
    if (r.orderType && r.orderType !== orderType) return false;
    return true;
  });

  if (candidates.length === 0) return null;

  // Sort by specificity (desc), then priority (desc)
  candidates.sort((a, b) => {
    const specDiff = specificityScore(b) - specificityScore(a);
    if (specDiff !== 0) return specDiff;
    return b.priority - a.priority;
  });

  const best = candidates[0]!;
  return {
    rule: best,
    costEffect: best.costEffect,
    chargeabilityEffect: best.chargeabilityEffect,
    costReductionPercent: best.costReductionPercent,
  };
}

/**
 * Apply cost effect to a cost value.
 */
export function applyCostEffect(
  normalCostCents: number,
  costEffect: CostEffect,
  reductionPercent: number | null,
): number {
  switch (costEffect) {
    case "CHARGE":
      return normalCostCents;
    case "ZERO":
      return 0;
    case "REDUCE":
      return Math.round(normalCostCents * (100 - (reductionPercent ?? 0)) / 100);
  }
}
