import Link from "next/link";
import { JobCounters, pickCounters } from "@/components/jobs/job-counters";
import { ErrorsCsvLink } from "@/components/keywords/errors-csv-link";
import { countryBreakdowns } from "@/lib/import-report";
import type { ImportReport } from "@/lib/imports";
import { keywordsHref } from "@/lib/keywords-scope";

// Rapport final d'un import (§4.5) : compteurs, ventilation du cloisonnement par pays, lignes
// en erreur, liste créée. Rendu par le wizard à la fin du job comme par la page de détail —
// une seule définition, deux usages.

/**
 * Compteurs du rapport final, dans l'ordre où ils se lisent.
 *
 * `rows_off_target` et `rows_country_unresolved` sont deux SOUS-ENSEMBLES de `rows_ignored`,
 * qui reste le total (il agrège aussi le rejeu d'un fichier déjà importé) : d'où le « dont ».
 * Leurs libellés sont ceux du résumé de listing (`reportSummary`, `lib/imports.ts`).
 *
 * Cette liste sert AUSSI aux compteurs de progression (`import-job-status.tsx`), qui lisent
 * `progress.counters` — la ventilation n'y voyage pas (elle est recalculée à chaque run, y
 * compris à la reprise), et une clé absente est simplement tue par `pickCounters`.
 */
export const REPORT_FIELDS = [
  { key: "rows_read", label: "Lignes lues" },
  { key: "rows_inserted", label: "Lignes insérées" },
  { key: "rows_ignored", label: "Lignes ignorées" },
  { key: "rows_off_target", label: "dont hors cible" },
  { key: "rows_country_unresolved", label: "dont pays non reconnu" },
  { key: "rows_error", label: "Lignes en erreur" },
  { key: "keywords_created", label: "Mots-clés créés" },
  { key: "metrics_written", label: "Métriques écrites" },
  { key: "list_items_added", label: "Ajouts à la liste" },
  { key: "maps_written", label: "Attaches URL" },
];

const numberFormat = new Intl.NumberFormat("fr-FR");

/**
 * Les lignes écartées par le cloisonnement, détaillées par libellé de pays TEL QU'IL EST
 * ÉCRIT DANS LE FICHIER (« United Kingdom », « New York ») — c'est ce libellé brut, et non un
 * code, qui permet de reconnaître un trou de table d'alias.
 *
 * Bloc distinct des compteurs : `JobCounters` n'affiche que des nombres finis et écarterait
 * silencieusement un dictionnaire. Rendu en liste qui se replie, jamais en table : une
 * répartition peut compter onze pays et la fenêtre ne doit jamais défiler horizontalement.
 *
 * `min-w-0 break-words` sur chaque entrée, et les DEUX sont nécessaires — mesuré à 375 px sur
 * un libellé d'un seul mot de soixante caractères (ce que peut contenir la colonne d'un
 * `generic_csv` mal désigné) : `break-words` seul ne coupe rien, parce qu'un item de flex a
 * `min-width: auto`, c'est-à-dire sa largeur min-content, et l'entrée dépassait de 66 px ;
 * `min-w-0` seul laisse la boîte à la bonne largeur mais le texte déborde quand même. Et le
 * `Card` étant `overflow-hidden`, ce débordement ne fait PAS défiler la fenêtre : il coupe
 * le libellé sans rien dire — le pire des deux.
 */
function CountryBreakdownList({ report }: { report: ImportReport }) {
  const blocks = countryBreakdowns(report);
  if (blocks.length === 0) return null;
  return (
    <div className="space-y-2">
      <h3 className="text-sm font-medium">Lignes écartées par pays</h3>
      <dl className="space-y-2">
        {blocks.map((block) => (
          <div key={block.key} className="min-w-0">
            <dt className="text-muted-foreground text-xs">
              {numberFormat.format(block.rows)} ignorées — {block.motive}
            </dt>
            <dd>
              <ul className="flex flex-wrap gap-x-3 gap-y-1 text-sm">
                {block.entries.map((entry) => (
                  <li key={entry.label} className="min-w-0 break-words">
                    {entry.label}{" "}
                    <span className="font-medium tabular-nums">
                      {numberFormat.format(entry.rows)}
                    </span>
                  </li>
                ))}
              </ul>
            </dd>
          </div>
        ))}
      </dl>
    </div>
  );
}

export function ImportReportView({
  report,
  error,
  importId,
  listId,
  siteId,
  targetId,
}: {
  report: ImportReport | null;
  /**
   * Le motif d'échec, quand il y en a un. Il n'est pas rendu ici — l'appelant a déjà sa place
   * pour l'afficher (`JobWatcher`, la page de détail) — mais il **interdit** le « Aucun rapport
   * pour l'instant. » : un import qui a échoué n'attend pas son rapport, il n'en aura jamais.
   * C'est ce message qui rendait un échec muet à l'écran.
   */
  error?: string | null;
  importId: string;
  listId?: string | null;
  siteId?: string | null;
  targetId?: string | null;
}) {
  if (report === null) {
    if (error) return null;
    return <p className="text-muted-foreground text-sm">Aucun rapport pour l'instant.</p>;
  }
  const errors = report.errors ?? [];
  return (
    <div className="space-y-4">
      <JobCounters counters={pickCounters(report, REPORT_FIELDS)} />

      <CountryBreakdownList report={report} />

      {siteId ? (
        <p className="text-sm">
          <Link
            href={keywordsHref(siteId, "", { target: targetId, list_id: listId })}
            className="underline underline-offset-4"
          >
            {listId ? "Voir la liste dans le réservoir" : "Voir le réservoir de la cible"}
          </Link>
        </p>
      ) : null}

      {report.errors_csv ? (
        <ErrorsCsvLink importId={importId} truncated={report.errors_complete === false} />
      ) : null}

      {errors.length > 0 ? (
        <details className="text-sm">
          <summary className="cursor-pointer">
            Premières lignes en erreur ({errors.length}
            {typeof report.errors_total === "number" && report.errors_total > errors.length
              ? ` sur ${report.errors_total}`
              : ""}
            )
          </summary>
          <ul className="mt-2 space-y-1">
            {errors.slice(0, 20).map((row) => (
              <li key={row.line} className="text-muted-foreground">
                Ligne {row.line} — {row.reason}
              </li>
            ))}
          </ul>
        </details>
      ) : null}
    </div>
  );
}
