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

/** The one `TechStepLlmService` method this job needs — same "structural, not the full class" reasoning as `audit-low-confidence.ts`'s own `ClauseJudge`. */
type TrainingDataSuggester = Pick<TechStepLlmService, "suggestTrainingData">;

/**
 * Point 3 of this feature's plan ("boucle de rétro-action... entraîner le
 * NLP selon les retours utilisateurs"): drains `StepTechStepCorrection`
 * rows a viewer submitted (`StepDescription.tsx`'s editable mode,
 * `apps/web`) that haven't been turned into a suggestion yet (`GET
 * /internal/tech-steps/pending-corrections`), and asks the LLM to propose
 * new training synonyms/utterances for each one's asserted technique.
 *
 * `getPendingCorrections` never returns a pure-removal correction
 * (`correctedTechStepKey: null`, "no technique belongs here") in the first
 * place — see that route's own doc comment (`tech-step-worker.service.ts`)
 * for why: there's no technique to propose new positive training data
 * *for* from a removal alone, and letting one through here would leave it
 * permanently stuck unconsumed. The `continue` below is a defensive
 * backstop against that invariant changing later, not the primary
 * filtering mechanism.
 *
 * @returns How many suggestions this run produced — same "log line only" purpose as `runAuditLowConfidenceJob`'s own return value.
 */
export async function runTransformCorrectionsJob(
  llm: TrainingDataSuggester,
  options: { limit: number },
): Promise<number> {
  const corrections = await getPendingCorrections(options.limit);

  const suggestions: TrainingSuggestionInput[] = [];
  for (const correction of corrections) {
    if (correction.correctedTechStepKey === null) continue;

    const result = await llm.suggestTrainingData(
      correction.clauseText,
      correction.correctedTechStepKey,
      // No per-recipe locale field exists yet anywhere in the app (see
      // `recipe.service.ts`'s own `DEFAULT_TECH_STEP_LOCALE` comment) —
      // "fr" is the only locale a real correction can meaningfully be in
      // today.
      "fr",
    );
    if (result.suggestedSynonyms.length === 0 && result.suggestedUtterances.length === 0) {
      // A run that produced nothing usable for this correction still
      // leaves it unconsumed (no suggestion was posted for it) — it's
      // retried on the next scheduled run rather than silently dropped,
      // on the theory that a transient bad generation shouldn't
      // permanently forfeit a real user correction's training value.
      continue;
    }

    suggestions.push({
      techStepKey: correction.correctedTechStepKey,
      locale: "fr",
      suggestedSynonyms: result.suggestedSynonyms,
      suggestedUtterances: result.suggestedUtterances,
      sourceType: "correction",
      sourceCorrectionId: correction.id,
    });
  }

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