// src/lib/semantic/serp-payload.ts — fonctions pures (payload/erreur) extraites
// de `actions.ts` : ce module n'est PAS "use server" et peut donc exporter des
// fonctions synchrones (Next.js interdit ça dans un module "use server").
import { AnalyticsJobError } from "@/lib/analytics/enqueue";
import type { SerpSnapshot } from "@/lib/keywords/serp-types";
import type { SerpSemanticsPayload } from "./profile-types";

export type SerpSemanticsOpts = {
  excludedPositions?: number[];
  clientUrl?: string;
};

type SerpRow = {
  serp: Record<string, SerpSnapshot>;
  country: string;
};

/**
 * Pure : construit le payload du job à partir de la ligne `keywords` lue et
 * des options de curation. `null` quand il n'y a pas de snapshot SERP pour le
 * pays de référence du mot-clé (`keywords.country`) — l'appelant renvoie alors
 * `{ ok:false, error:"no_serp" }`. Testable sans DB ni mock.
 */
export function buildSerpSemanticsPayload(
  keywordId: string,
  row: SerpRow,
  opts?: SerpSemanticsOpts,
): SerpSemanticsPayload | null {
  const snap = row.serp[row.country];
  if (!snap || snap.competitors.length === 0) return null;

  const excluded = new Set(opts?.excludedPositions ?? []);
  const urls = snap.competitors
    // Clamp [1,10] : une position hors-plage fausserait silencieusement le
    // poids CTR côté wasm (même contrainte que le runner, en défense en
    // profondeur — voir analysis-runner.ts `clampAndDedupPositions`).
    .filter((c) => c.position >= 1 && c.position <= 10)
    .map((c) => ({
      position: c.position,
      url: c.url,
      included: !excluded.has(c.position),
    }));

  return {
    keywordId,
    country: row.country,
    urls,
    ...(opts?.clientUrl ? { clientUrl: opts.clientUrl } : {}),
  };
}

/**
 * Pure : dérive un code d'erreur stable à partir de l'exception levée par
 * `enqueueAnalyticsJob`. `409` (le service refuse une seconde analyse
 * `queued|running` pour le même `keywordId`, voir enqueue.ts) → déjà en
 * cours ; toute autre erreur réseau/service → échec générique. Testable
 * sans réseau.
 */
export function mapEnqueueError(
  err: unknown,
): "already_running" | "enqueue_failed" {
  if (err instanceof AnalyticsJobError && err.status === 409) {
    return "already_running";
  }
  return "enqueue_failed";
}
