import type { CalculationType, EntityCategory } from "@/lib/api";

type EditableFieldMap = EntityCategory["editableFields"];
type UnitLabelMap = EntityCategory["unitLabels"];

export type CategoryUnitMode = "none" | "tiered" | "single";

export interface CalculationTypeOption {
  value: CalculationType;
  label: string;
  description: string;
  unitMode: CategoryUnitMode;
  recommendedEditableFields: EditableFieldMap;
  recommendedUnitLabels: UnitLabelMap;
}

export const CALCULATION_TYPE_OPTIONS: CalculationTypeOption[] = [
  {
    value: "manual",
    label: "Manual Pricing",
    description:
      "Estimator edits cost, markup, and price directly. Best for flexible categories without an automatic pricing source.",
    unitMode: "none",
    recommendedEditableFields: { quantity: true, cost: true, markup: true, price: true, tierUnits: false },
    recommendedUnitLabels: {},
  },
  {
    value: "direct_total",
    label: "Direct Total",
    description: "Estimator enters the sell value directly. Cost and markup are derived or suppressed.",
    unitMode: "none",
    recommendedEditableFields: { quantity: false, cost: false, markup: false, price: true, tierUnits: false },
    recommendedUnitLabels: {},
  },
  {
    value: "formula",
    label: "Custom Formula",
    description:
      "Bidwright calculates the line from a custom formula using quantity, cost, markup, price, and per-tier hours.",
    unitMode: "tiered",
    recommendedEditableFields: { quantity: true, cost: true, markup: true, price: false, tierUnits: true },
    recommendedUnitLabels: {},
  },
  {
    value: "tiered_rate",
    label: "Tiered Rate Schedule",
    description:
      "Uses linked rate-schedule tiers. Hours are entered per tier in tierUnits.",
    unitMode: "tiered",
    recommendedEditableFields: { quantity: true, cost: false, markup: false, price: false, tierUnits: true },
    recommendedUnitLabels: {},
  },
  {
    value: "duration_rate",
    label: "Duration / Usage Pricing",
    description:
      "Uses linked rate-schedule tiers (DAY/WEEK/MONTH or similar). Duration counts entered per tier in tierUnits.",
    unitMode: "tiered",
    recommendedEditableFields: { quantity: true, cost: false, markup: false, price: false, tierUnits: true },
    recommendedUnitLabels: {},
  },
  {
    value: "quantity_markup",
    label: "Quantity x Cost + Markup",
    description: "Automatically extends quantity and cost, then applies markup for sell pricing.",
    unitMode: "none",
    recommendedEditableFields: { quantity: true, cost: true, markup: true, price: false, tierUnits: false },
    recommendedUnitLabels: {},
  },
  {
    value: "unit_markup",
    label: "Unit Cost + Markup",
    description: "Calculates sell value from quantity, unit cost, and markup while keeping pricing controlled.",
    unitMode: "none",
    recommendedEditableFields: { quantity: true, cost: true, markup: true, price: false, tierUnits: false },
    recommendedUnitLabels: {},
  },
  {
    value: "unit_rate",
    label: "Quantity × Units × Cost",
    description:
      "Multiplies quantity by a single Units count and unit cost — e.g. 6 people × 5 days × per-diem rate. One Units input per row (no rate schedule needed). Best for travel, per diem, and other “N of something for M periods” lines.",
    unitMode: "single",
    recommendedEditableFields: { quantity: true, cost: true, markup: true, price: false, tierUnits: true },
    recommendedUnitLabels: {},
  },
];

const CALCULATION_TYPE_MAP = new Map(
  CALCULATION_TYPE_OPTIONS.map((option) => [option.value, option]),
);

export function getCalculationTypeOption(value: CalculationType | string | undefined) {
  if (value && CALCULATION_TYPE_MAP.has(value as CalculationType)) {
    return CALCULATION_TYPE_MAP.get(value as CalculationType)!;
  }
  return CALCULATION_TYPE_MAP.get("manual")!;
}

export function categoryUsesTieredUnits(category: Pick<EntityCategory, "calculationType" | "itemSource"> | undefined) {
  if (category?.itemSource === "rate_schedule") return true;
  return getCalculationTypeOption(category?.calculationType).unitMode === "tiered";
}

export type CategoryUnitInputMode = "none" | "multiplier" | "duration" | "single";

/**
 * How a category's per-row "units" are entered:
 *  - "multiplier": one input per rate-schedule tier, keyed by tier multiplier
 *    (Labour Reg/OT/DT). Hours are entered per tier in tierUnits.
 *  - "duration": a single usage/duration count priced against the rate tier that
 *    matches the row's UoM — owned/rented equipment on a Daily/Weekly/Monthly
 *    ratebook. One Units input; the UoM picks the tier/rate.
 *  - "single": a single Units count (no rate schedule) that multiplies
 *    quantity × cost — e.g. travel/per-diem priced as people × days × rate.
 *  - "none": no tier units; priced from quantity/cost/markup/price (e.g. a
 *    freeform vendor-quote rental, material, etc.).
 * Driven purely by category config so it generalises across org setups.
 */
export function categoryUnitInputMode(
  category: Pick<EntityCategory, "calculationType" | "itemSource"> | undefined,
): CategoryUnitInputMode {
  if (category?.calculationType === "duration_rate") {
    // A rate-book-backed duration line prices at the UoM tier (rate × duration ×
    // qty) so the UoM picks the rate. A *freeform* duration line has no rate book
    // to look up, so it is a single Quantity × Units × Cost line (same one-input
    // UI; the engine prices it differently).
    return category?.itemSource === "rate_schedule" ? "duration" : "single";
  }
  if (getCalculationTypeOption(category?.calculationType).unitMode === "single") return "single";
  if (categoryUsesTieredUnits(category)) return "multiplier";
  return "none";
}

export function categoryAllowsEditingTierUnits(
  category: Pick<EntityCategory, "calculationType" | "editableFields" | "itemSource"> | undefined,
) {
  if (!category) return true;
  if (category.itemSource === "rate_schedule") return true;
  if (categoryUsesTieredUnits(category)) return true;
  return Boolean(category.editableFields?.tierUnits);
}

export function getTierLabel(
  category: Pick<EntityCategory, "unitLabels"> | undefined,
  tierId: string,
  fallback?: string,
) {
  const label = category?.unitLabels?.[tierId];
  if (typeof label === "string" && label.trim()) return label.trim();
  return fallback ?? "";
}

export function getCalculationPreset(type: CalculationType) {
  const option = getCalculationTypeOption(type);
  return {
    editableFields: { ...option.recommendedEditableFields },
    unitLabels: { ...option.recommendedUnitLabels },
  };
}
