// Helpers et types pour les flows /report-templates côté panel.
// La doc de référence pour les contrats (diff/apply) est le handoff Q4
// (~/projects/missioflow-handoff.md). Les algos de normalisation viennent de
// `ReportTemplateDiffBuilder::normItemForDiff()` côté missioflow-app — on les
// reproduit fidèlement ici pour que le `pairKey` matche celui calculé côté
// serveur dans `ReportTemplatesApplyService::buildPairKey()`.

import type { DiffPair, DiffTemplate } from "./types";

/** Choix par pair : on garde la valeur XLSX, ou on garde la valeur BDD. */
export type PairChoice = "xlsx" | "db";

/** Map d'override d'utilisateur, indexée par `pair_uid`. */
export type SelectionMap = Record<string, PairChoice>;

/** Format envoyé au backend (JSON-stringifié) pour le champ `selections`. */
export type ApplySelections = Record<
  string,
  { keep_xlsx: boolean; keep_db: boolean }
>;

/**
 * Normalise un libellé de step pour que le pairKey matche celui calculé
 * côté backend. Algo : uppercase, collapse des espaces multiples, trim des
 * espaces et points en fin.
 */
export function normItem(item: string | null | undefined): string {
  if (!item) return "";
  return item
    .toUpperCase()
    .replace(/\s+/g, " ")
    .replace(/[.\s]+$/, "")
    .trim();
}

/** Construit la clé canonique d'une pair pour le map `selections`. */
export function buildPairKey(sheetName: string, pair: DiffPair): string {
  const xlsxItem =
    pair.xlsx && typeof pair.xlsx.item === "string"
      ? (pair.xlsx.item as string)
      : "";
  const dbItem =
    pair.db && typeof pair.db.item === "string"
      ? (pair.db.item as string)
      : "";
  return `${sheetName}||${pair.pair_uid}||${normItem(xlsxItem)}||${normItem(dbItem)}`;
}

/**
 * Choix par défaut selon la catégorie de la pair. Stratégie "import du
 * nouveau XLSX" : on prend la valeur XLSX par défaut quand elle existe et
 * apporte de la nouveauté (ajouts / modifs / renames). On préserve la BDD
 * sinon (orphelins, volontaires). L'utilisateur peut override ligne par ligne.
 */
export const DEFAULT_PAIR_CHOICE: Record<DiffPair["category"], PairChoice> = {
  common: "db",
  common_divergent: "xlsx",
  rename: "xlsx",
  xlsx_only: "xlsx",
  db_only_volontaire: "db",
  db_only_orphan: "db",
};

/**
 * Compile les overrides utilisateur en map `pairKey → {keep_xlsx,keep_db}`.
 * Skippe les pairs `common` (no-op : la BDD est déjà identique au XLSX).
 */
export function compileSelections(
  template: DiffTemplate,
  overrides: SelectionMap,
): ApplySelections {
  const out: ApplySelections = {};
  for (const phase of template.phases ?? []) {
    for (const pair of phase.pairs ?? []) {
      if (pair.category === "common") continue;
      const choice =
        overrides[pair.pair_uid] ?? DEFAULT_PAIR_CHOICE[pair.category];
      const key = buildPairKey(template.sheet_name, pair);
      out[key] = {
        keep_xlsx: choice === "xlsx",
        keep_db: choice === "db",
      };
    }
  }
  return out;
}

/**
 * Liste les pairs pour lesquelles l'utilisateur peut faire un choix XLSX/BDD.
 * Exclut les `common` (rien à choisir).
 */
export function selectablePairs(
  template: DiffTemplate,
): Array<{ phaseIndex: number; phaseName: string; pair: DiffPair }> {
  const out: Array<{ phaseIndex: number; phaseName: string; pair: DiffPair }> =
    [];
  for (const phase of template.phases ?? []) {
    for (const pair of phase.pairs ?? []) {
      if (pair.category === "common") continue;
      out.push({
        phaseIndex: phase.index,
        phaseName: phase.xlsx_name || phase.db_name || "",
        pair,
      });
    }
  }
  return out;
}
