// Frontend Evals helpers — PR e2 switched the data source from
// localStorage to the real `/v1/datasets` + `/v1/eval_runs` endpoints
// (see api-client.jsx). What stays here:
//
//   - GRADER_LIBRARY: the catalog of grader_ids the UI offers. PR e4 will
//     wire real implementations on the backend; for now the catalog only
//     exists in the frontend (datasets carry grader_ids strings; the
//     backend just round-trips them without validating yet).
//
//   - decorateDataset / decorateCase: thin adapters that alias the
//     backend snake_case fields to the camelCase / `id` that existing
//     UI components reference, so PR e2 didn't have to touch every
//     render line. Future cleanup PR can drop the aliases and read
//     `dataset_id` directly.
//
// Previously this file also held seedDatasets() / seedRuns() / a Store
// object that persisted everything to localStorage. All gone — the
// real backend (PR e1) is now the source of truth.

const GRADER_LIBRARY = [
  { id: "exact_match",      name: "exact_match",      desc: "Output equals expected (strict).",       kind: "deterministic" },
  { id: "contains",         name: "contains",         desc: "Output contains the expected substring.", kind: "deterministic" },
  { id: "regex",            name: "regex",            desc: "Output matches a regex pattern.",        kind: "deterministic" },
  { id: "json_schema",      name: "json_schema",      desc: "Output validates against a JSON schema.", kind: "deterministic" },
  { id: "llm_helpfulness",  name: "llm.helpfulness",  desc: "LLM-as-judge on a 1-5 helpfulness rubric.", kind: "llm" },
  { id: "llm_faithfulness", name: "llm.faithfulness", desc: "LLM-as-judge: no claim is unsupported.",   kind: "llm" },
  { id: "tool_called",      name: "tool_called",      desc: "Agent called the listed tool(s).",       kind: "trajectory" },
  { id: "trajectory_match", name: "trajectory_match", desc: "Tool call sequence matches expected.",   kind: "trajectory" },
  { id: "no_extra_tools",   name: "no_extra_tools",   desc: "Agent did not call un-whitelisted tools.", kind: "trajectory" },
  { id: "max_cost",         name: "max_cost",         desc: "Run cost stays under threshold.",        kind: "budget" },
  { id: "max_latency",      name: "max_latency",      desc: "Run latency stays under threshold.",     kind: "budget" },
];

// Backend → UI shape adapter. The existing components read `id`,
// `createdAt` (ms), `cases` (array even when missing). Keep the rest of
// the API response as-is so dataset_id etc. are still available if a
// component wants them.
function decorateDataset(apiDs) {
  if (!apiDs) return null;
  return {
    ...apiDs,
    id: apiDs.dataset_id,
    createdAt: (apiDs.created_at || 0) * 1000,
    cases: (apiDs.cases || []).map(decorateCase),
  };
}

function decorateCase(apiCase) {
  if (!apiCase) return null;
  return {
    ...apiCase,
    id: apiCase.case_id,
    addedAt: (apiCase.added_at || 0) * 1000,
  };
}

// EvalRun (PR e3 will wire execution; for now status is always "pending"
// and cases[] is empty). UI components that previously read the seeded
// mock shape need adapters too — keep them simple.
function decorateEvalRun(apiRun) {
  if (!apiRun) return null;
  const epochMs = (value) => value && value < 100000000000 ? value * 1000 : value;
  return {
    ...apiRun,
    id: apiRun.eval_run_id,
    datasetId: apiRun.dataset_id,
    datasetName: apiRun.dataset_name,
    agentId: apiRun.agent_id,
    agentName: apiRun.agent_name,
    // Eval `started_at` is already milliseconds, unlike dataset timestamps.
    startedAt: epochMs(apiRun.started_at || apiRun.created_at || 0),
    durationMs: apiRun.duration_ms || 0,
    cases: (apiRun.cases || []).map((c) => ({
      ...c,
      caseId: c.case_id,
      latencyMs: c.latency_ms,
      costUSD: c.cost_usd,
      inputTokens: c.input_tokens,
      outputTokens: c.output_tokens,
      pass: c.passed,
    })),
  };
}

Object.assign(window, {
  GRADER_LIBRARY,
  decorateDataset,
  decorateCase,
  decorateEvalRun,
});
