import { ROUTE_LEGS } from '../mocks/route';
import type { RouteLeg } from '../types/timeline';

const MILEAGE_ROUND_M = 10;
const METERS_PER_KM = 1000;

/** Mileage in meters at a cursor px, via piecewise-linear leg anchors. */
export function mileageAtPx(px: number, legs: RouteLeg[] = ROUTE_LEGS): number {
  const leg =
    legs.find((l) => px >= l.startPx && px <= l.endPx) ?? legs[legs.length - 1];
  const anchors = leg.anchors;
  for (let i = 0; i < anchors.length - 1; i++) {
    const a = anchors[i];
    const b = anchors[i + 1];
    if (px <= b.px || i === anchors.length - 2) {
      const t = Math.min(1, Math.max(0, (px - a.px) / (b.px - a.px)));
      return a.mileage + (b.mileage - a.mileage) * t;
    }
  }
  return anchors[0].mileage;
}

/**
 * First px at which the given mileage occurs. Leg start anchors win so a jump
 * to a turn mileage lands on the start of that leg.
 */
export function pxForMileage(
  mileage: number,
  legs: RouteLeg[] = ROUTE_LEGS,
): number | null {
  for (const leg of legs) {
    if (leg.anchors[0].mileage === mileage) return leg.startPx;
  }
  for (const leg of legs) {
    const anchors = leg.anchors;
    for (let i = 0; i < anchors.length - 1; i++) {
      const a = anchors[i];
      const b = anchors[i + 1];
      const lo = Math.min(a.mileage, b.mileage);
      const hi = Math.max(a.mileage, b.mileage);
      if (mileage >= lo && mileage <= hi) {
        return a.px + (b.px - a.px) * ((mileage - a.mileage) / (b.mileage - a.mileage));
      }
    }
  }
  return null;
}

/** 158204 → "158+200". */
export function formatMileage(mileage: number): string {
  const rounded = Math.round(mileage / MILEAGE_ROUND_M) * MILEAGE_ROUND_M;
  const km = Math.floor(rounded / METERS_PER_KM);
  const m = rounded % METERS_PER_KM;
  return `${km}+${String(m).padStart(3, '0')}`;
}

/** Accepts "158k200", "158200", "161800"… Returns meters or null. */
export function parseMileageQuery(raw: string): number | null {
  const digits = raw.toLowerCase().replace(/k/g, '').replace(/[^0-9]/g, '');
  const mileage = parseInt(digits, 10);
  return Number.isFinite(mileage) && mileage > 0 ? mileage : null;
}
