/**
 * Per-engine quality from run history (§2 cost/latency-aware routing).
 *
 * PURE + synchronous: given a set of completed runs, derive a `(engine) => [0,1]`
 * quality lookup the scheduler's soft `engineQuality` term consumes. 1 = the
 * historically cheapest + fastest engine; lower = more expensive / slower.
 *
 * Design choices that keep this a safe, gentle nudge:
 *  • Scores are RELATIVE: the cheapest observed engine anchors costScore = 1, the
 *    fastest anchors durationScore = 1; others decay proportionally. With a single
 *    engine (or no data) every engine scores 1 ⇒ the term is inert.
 *  • Engines with NO history return the neutral 1 — history can only DEMOTE a
 *    demonstrably costly/slow engine, never penalise a new/unknown one.
 *  • Cost and duration are averaged independently and combined 50/50; an engine
 *    with only one signal uses whichever it has.
 */

import type { FleetRunDoc } from './types.js';

interface Accum {
  costSum: number;
  costN: number;
  durSum: number;
  durN: number;
}

/** Per-engine averages plus the final blended quality in [0,1]. */
export interface EngineQualityEntry {
  engine: string;
  avgCostUsd: number | null;
  avgDurationMs: number | null;
  /** Runs that contributed at least one signal (cost or duration). */
  samples: number;
  quality: number;
}

export interface EngineQuality {
  byEngine: Map<string, EngineQualityEntry>;
  /** Lookup for the scheduler: unknown / no-history engines ⇒ neutral 1. */
  lookup: (engine: string | undefined) => number;
}

/** The engine a run actually used: the factory-reported concrete engine wins,
 *  else the engine the run was created with. */
function runEngine(run: FleetRunDoc): string | undefined {
  return run.insights?.engine ?? run.engine;
}

function runDurationMs(run: FleetRunDoc): number | null {
  if (!run.endedAt) return null;
  const start = Date.parse(run.startedAt);
  const end = Date.parse(run.endedAt);
  if (Number.isNaN(start) || Number.isNaN(end) || end < start) return null;
  return end - start;
}

/**
 * Build the per-engine quality lookup from `runs`. Only runs with a known engine
 * and at least one usable signal (positive cost or a valid duration) contribute.
 */
export function computeEngineQuality(runs: readonly FleetRunDoc[]): EngineQuality {
  const acc = new Map<string, Accum>();
  for (const run of runs) {
    const engine = runEngine(run);
    if (!engine || engine === 'unknown') continue;
    const cost = run.insights?.costUsd;
    const dur = runDurationMs(run);
    const hasCost = typeof cost === 'number' && cost > 0;
    if (!hasCost && dur === null) continue;
    const a = acc.get(engine) ?? { costSum: 0, costN: 0, durSum: 0, durN: 0 };
    if (hasCost) {
      a.costSum += cost as number;
      a.costN += 1;
    }
    if (dur !== null) {
      a.durSum += dur;
      a.durN += 1;
    }
    acc.set(engine, a);
  }

  // Anchors: the cheapest avg cost and the fastest avg duration across engines.
  let minAvgCost = Infinity;
  let minAvgDur = Infinity;
  const avgs = new Map<string, { cost: number | null; dur: number | null; samples: number }>();
  for (const [engine, a] of acc) {
    const cost = a.costN > 0 ? a.costSum / a.costN : null;
    const dur = a.durN > 0 ? a.durSum / a.durN : null;
    avgs.set(engine, { cost, dur, samples: Math.max(a.costN, a.durN) });
    if (cost !== null && cost < minAvgCost) minAvgCost = cost;
    if (dur !== null && dur < minAvgDur) minAvgDur = dur;
  }

  const byEngine = new Map<string, EngineQualityEntry>();
  for (const [engine, { cost, dur, samples }] of avgs) {
    // Relative scores in (0,1]: cheapest/fastest = 1, others decay proportionally.
    const costScore = cost !== null && cost > 0 ? minAvgCost / cost : cost === 0 ? 1 : null;
    const durScore = dur !== null && dur > 0 ? minAvgDur / dur : dur === 0 ? 1 : null;
    const parts = [costScore, durScore].filter((s): s is number => s !== null);
    const quality = parts.length > 0 ? parts.reduce((s, v) => s + v, 0) / parts.length : 1;
    byEngine.set(engine, {
      engine,
      avgCostUsd: cost,
      avgDurationMs: dur,
      samples,
      quality,
    });
  }

  const lookup = (engine: string | undefined): number => {
    if (!engine) return 1;
    return byEngine.get(engine)?.quality ?? 1;
  };

  return { byEngine, lookup };
}

/**
 * `FLEET_COST_ROUTING` env gate — default OFF. When enabled, the coordinator
 * injects the engine-quality lookup into the scheduler so cost/latency history
 * gently biases routing. Off ⇒ the soft term stays inert (no behavior change).
 */
export function isCostRoutingEnabled(): boolean {
  const v = (process.env.FLEET_COST_ROUTING ?? '').trim().toLowerCase();
  return v === '1' || v === 'true' || v === 'on' || v === 'yes';
}
