import type { Keyword } from "./types";

export type TargetStatus = "candidate" | "planned" | "live";

export interface TargetCountry {
  code: string;
  label: string;
}

/**
 * Fixed proto target markets (English markets, matching the en/US fixtures).
 * The flag is derived from `code` via `<Flag>` at the consumer — never stored.
 */
export const TARGET_COUNTRIES: TargetCountry[] = [
  { code: "US", label: "États-Unis" },
  { code: "GB", label: "Royaume-Uni" },
  { code: "CA", label: "Canada" },
  { code: "AU", label: "Australie" },
];

/** keywordId -> (country code -> status). No entry = "non ciblé". */
export type TargetsState = Record<
  string,
  Partial<Record<string, TargetStatus>>
>;

const STATUS_RANK: Record<TargetStatus, number> = {
  candidate: 1,
  planned: 2,
  live: 3,
};

/**
 * Statuts de ciblage qui valent « c'est déjà fait » pour l'étape
 * `target-country` du parcours d'entrée.
 *
 * La ligne passe EXACTEMENT là où passe `STATUS_RANK` ci-dessus : on écarte ce
 * qui est au niveau de `planned` ou au-dessus, jamais en dessous.
 *
 * `candidate` en est donc absent, et c'est le cœur de la règle : c'est le
 * statut PAR DÉFAUT de `setKeywordTargetsBulkAction` comme du ciblage de la
 * matrice Recherche, un réservoir travaillé en contient couramment des
 * dizaines, et aucun d'eux ne constitue un plan. Les exclure des candidats
 * ferait dire à l'étape « ton réservoir est encore vide » devant un réservoir
 * plein, en invitant à le peupler : le message mentirait et le geste proposé ne
 * débloquerait rien. Re-cibler un `candidate` en `planned` est une PROMOTION —
 * précisément ce que l'étape est là pour faire.
 *
 * ⚠️ La constante est PARTAGÉE par les deux couches qui posent la même
 * question, et elle doit le rester :
 *   - `getTargetCandidates` (`./queries`) s'en sert pour retirer des candidats
 *     proposés ce qui est déjà planifié ou publié ;
 *   - `deriveActivationFlags` (`@/lib/onboarding/activation/derive`) s'en sert
 *     pour cocher le drapeau `target-country`.
 * Dupliquée, elle a déjà divergé : la dérivation ne regardait que `planned`,
 * si bien qu'un plan passé en `live` (par `createContentItemAction`) ou un
 * unique ciblage `planned` retiré de la matrice DÉ-COCHAIT l'activation et
 * renvoyait l'utilisateur en plein écran sur le parcours d'entrée. Le succès du
 * produit ne doit jamais rouvrir le guide.
 */
export const EXCLUDED_TARGET_STATUSES: TargetStatus[] = ["planned", "live"];

const SEED_STATUSES: TargetStatus[] = ["candidate", "planned", "live"];

/**
 * Deterministic seed (no randomness — derived from index) so the matrix isn't
 * empty on load and tests are stable. Every 3rd keyword is left untargeted.
 */
export function seedTargets(keywords: Keyword[]): TargetsState {
  const state: TargetsState = {};
  keywords.forEach((k, i) => {
    if (i % 3 === 2) return; // leave untargeted
    const entry: Partial<Record<string, TargetStatus>> = {};
    const primary = TARGET_COUNTRIES[i % TARGET_COUNTRIES.length];
    entry[primary.code] = SEED_STATUSES[i % SEED_STATUSES.length];
    if (i % 2 === 0) {
      const secondary = TARGET_COUNTRIES[(i + 1) % TARGET_COUNTRIES.length];
      entry[secondary.code] = "candidate";
    }
    state[k.id] = entry;
  });
  return state;
}

/** Set (or clear, when status is null) one cell. Drops empty keyword entries. */
export function setCell(
  state: TargetsState,
  keywordId: string,
  country: string,
  status: TargetStatus | null,
): TargetsState {
  const entry = { ...(state[keywordId] ?? {}) };
  if (status === null) delete entry[country];
  else entry[country] = status;

  const next = { ...state };
  if (Object.keys(entry).length === 0) delete next[keywordId];
  else next[keywordId] = entry;
  return next;
}

/** Bulk-target keywords × countries; never downgrades a more-advanced status. */
export function setForSelected(
  state: TargetsState,
  keywordIds: string[],
  countries: string[],
  status: TargetStatus = "candidate",
): TargetsState {
  let next = state;
  for (const kwId of keywordIds) {
    for (const country of countries) {
      const current = next[kwId]?.[country];
      if (current && STATUS_RANK[current] >= STATUS_RANK[status]) continue;
      next = setCell(next, kwId, country, status);
    }
  }
  return next;
}

/**
 * Covered countries for a keyword, restricted to and ordered by `countries`
 * (the site's target countries). Targets in other countries — e.g. the legacy
 * proto seed (US/GB/CA/AU) on a FR-only site — are intentionally hidden.
 */
export function coverageOf(
  state: TargetsState,
  keywordId: string,
  countries: string[],
): { country: string; status: TargetStatus }[] {
  const entry = state[keywordId] ?? {};
  return countries
    .filter((code) => entry[code])
    .map((code) => ({ country: code, status: entry[code] as TargetStatus }));
}
