import {
  getAuditBatch,
  postTrainingSuggestions,
  type TrainingSuggestionInput,
} from "../api-client.js";
import type { TechStepLlmService } from "../llm-verdict.js";

/** The one `TechStepLlmService` method this job needs — accepted structurally rather than the full class, so a test can pass a plain fake object instead of a real, model-loaded instance. */
type ClauseJudge = Pick<TechStepLlmService, "judgeClause">;

/**
 * Point 2 of this feature's plan ("combiner NLP+LLM pour fiabiliser le
 * NLP"), realized entirely offline: samples clauses `tech-step-matcher.ts`'s
 * classifier itself was least confident about (`GET
 * /internal/tech-steps/audit-batch` — see that route's own doc comment for
 * exactly what "low-confidence" means there), asks the LLM for its own
 * verdict on each, and — only when the LLM disagrees with what the NLP
 * anchor already implied — proposes that clause as a new training
 * utterance for the technique the LLM preferred.
 *
 * Never touches the interactive recipe-save/read path — this feature's
 * plan explicitly chose offline-only for the LLM (no infra here to run an
 * LLM call within a request's own latency budget without risking it), so
 * the NLP classifier alone stays responsible for what a viewer sees
 * immediately; this job only ever improves the *corpus* it's trained on,
 * for future saves/backfills to benefit from.
 *
 * @returns How many suggestions this run produced — used only for the
 *   scheduler's own log line (`scheduler.ts`), not asserted on by anything.
 */
export async function runAuditLowConfidenceJob(
  llm: ClauseJudge,
  options: { locale: string; limit: number },
): Promise<number> {
  const clauses = await getAuditBatch(options.locale, options.limit);

  const suggestions: TrainingSuggestionInput[] = [];
  for (const clause of clauses) {
    const verdictKey = await llm.judgeClause(clause.clauseText);
    // No opinion, or agrees with what the NLP anchor already implied —
    // nothing new to propose either way. A clause with *no* anchor at all
    // never reaches this job in the first place (`getAuditBatch`'s own
    // filter, `tech-step-worker.service.ts`).
    if (verdictKey === null || verdictKey === clause.anchorKey) continue;

    suggestions.push({
      techStepKey: verdictKey,
      locale: clause.locale,
      // Only the clause itself, as one more training utterance — this job
      // has exactly one confirmed disagreement per clause, not enough to
      // responsibly invent new synonym *words* from (that needs the
      // richer signal `transform-corrections` has: a human explicitly
      // confirming the label, not just the LLM's own second opinion).
      suggestedSynonyms: [],
      suggestedUtterances: [clause.clauseText],
      sourceType: "llm_audit",
    });
  }

  await postTrainingSuggestions(suggestions);
  return suggestions.length;
}
