// src/lib/onboarding/first-target.ts — choix du mot-clé et du pays proposés
// pour le PREMIER ciblage du parcours d'entrée (étape `target-country`).
//
// Module PUR, sans import serveur : il est lu par le RSC `/onboarding` comme
// par l'étape cliente, et reste chargeable sous `--conditions=react-server`
// (le script `bun run test` du dépôt). Même motif que `gsc-step-logic.ts`,
// `keywords-step-logic.ts` et `enrich-step-logic.ts` : les règles de l'étape
// sont des propriétés testables plutôt que des promesses de JSX.
//
// ⚠️ Le pays vient du SITE, jamais d'une saisie. C'est précisément pourquoi le
// pays cible est devenu OBLIGATOIRE à la création (tâche 2) : sans lui, aucun
// candidat n'existe et cette étape — REQUISE — ne pourrait jamais être
// franchie. Les sites créés avant cette règle peuvent malgré tout arriver ici
// sans pays : `resolveFirstTargetState` nomme ce cas au lieu de rendre une
// carte vide.

/** Ligne du réservoir considérée pour le premier ciblage. */
export type TargetCandidate = {
  id: string;
  term: string;
  volume: number | null;
};

/** Cellule mot-clé × pays que l'étape écrira au statut `planned`. */
export type FirstTarget = { keywordId: string; country: string };

/**
 * Choisit le mot-clé et le pays à proposer pour le premier ciblage.
 * Volume décroissant, `null` en dernier — même ordre que l'index
 * keywords_site_volume_idx (volume DESC NULLS LAST).
 */
export function pickFirstTargetCandidate(
  candidates: readonly TargetCandidate[],
  countries: readonly string[],
): FirstTarget | null {
  // `countries[0]` peut être la chaîne vide sur un site antérieur à la garde
  // de saisie : la retenir écrirait un keyword_target sur un pays "", cellule
  // qu'aucune surface de l'app ne sait afficher.
  const country = countries[0];
  if (!country || candidates.length === 0) return null;

  // `sort` est stable depuis ES2019 : à volumes tous inconnus, l'ordre reçu du
  // serveur (déjà volume DESC NULLS LAST) est conservé, et on retombe donc sur
  // le premier candidat plutôt que sur un mot-clé tiré au hasard.
  const best = [...candidates].sort(
    (a, b) => (b.volume ?? -1) - (a.volume ?? -1),
  )[0];
  if (!best) return null;
  return { keywordId: best.id, country };
}

/**
 * État affichable de l'étape. `pickFirstTargetCandidate` rend `null` pour deux
 * raisons très différentes — site sans pays cible, ou réservoir vide — qui
 * appellent deux gestes opposés : corriger le site, ou importer des mots-clés.
 * Les confondre laisserait l'utilisateur devant une carte vide sans savoir quoi
 * réparer.
 */
export type FirstTargetState =
  | { kind: "ready"; target: FirstTarget; term: string }
  | { kind: "no-country" }
  | { kind: "no-keyword" };

export function resolveFirstTargetState(
  candidates: readonly TargetCandidate[],
  countries: readonly string[],
): FirstTargetState {
  // Le pays d'abord : c'est une propriété du SITE, et tant qu'il manque aucun
  // mot-clé — même importé dans la foulée — ne produirait de candidat.
  if (!countries[0]) return { kind: "no-country" };

  const target = pickFirstTargetCandidate(candidates, countries);
  if (!target) return { kind: "no-keyword" };

  const term = candidates.find((c) => c.id === target.keywordId)?.term;
  // Le terme vient du même tableau que la cible : il est toujours là. Le repli
  // ne sert qu'à ne pas rendre le type optionnel pour un cas impossible.
  if (!term) return { kind: "no-keyword" };

  return { kind: "ready", target, term };
}
