// src/lib/content/csv.ts — round-trip CSV des content_items (ELEVA-59).

import type { ContentStatus } from "@/lib/db/domain-schema";
import { csvField } from "@/lib/keywords/export-full";

const STATUSES: ContentStatus[] = [
  "idea",
  "brief",
  "writing",
  "review",
  "published",
];

/** Parser RFC-4180 minimal : quotes, "" échappé, retours ligne quotés, CRLF. */
export function parseCsv(text: string): string[][] {
  const rows: string[][] = [];
  let row: string[] = [];
  let field = "";
  let inQuotes = false;
  for (let i = 0; i < text.length; i++) {
    const c = text[i];
    if (inQuotes) {
      if (c === '"') {
        if (text[i + 1] === '"') {
          field += '"';
          i++;
        } else inQuotes = false;
      } else field += c;
    } else if (c === '"') {
      inQuotes = true;
    } else if (c === ",") {
      row.push(field);
      field = "";
    } else if (c === "\n" || c === "\r") {
      if (c === "\r" && text[i + 1] === "\n") i++;
      row.push(field);
      field = "";
      rows.push(row);
      row = [];
    } else field += c;
  }
  if (field !== "" || row.length > 0) {
    row.push(field);
    rows.push(row);
  }
  // ignore les lignes entièrement vides (ex. ligne finale)
  return rows.filter((r) => r.some((f) => f.trim() !== ""));
}

export type ContentExportRow = {
  title: string;
  status: ContentStatus;
  primaryKeywordTerm: string | null;
  secondaryKeywordTerms: string[];
  lang: string | null;
  country: string | null;
  assignee: string | null;
  dueDate: string | null; // YYYY-MM-DD
  url: string | null;
};

const HEADER = [
  "Titre",
  "Statut",
  "Mot-clé principal",
  "Mots-clés secondaires",
  "Langue",
  "Pays",
  "Assigné",
  "Échéance",
  "URL",
];

export function buildContentCsv(rows: ContentExportRow[]): string {
  const lines = [HEADER.join(",")];
  for (const r of rows) {
    lines.push(
      [
        r.title,
        r.status,
        r.primaryKeywordTerm ?? "",
        r.secondaryKeywordTerms.join("|"),
        r.lang ?? "",
        r.country ?? "",
        r.assignee ?? "",
        r.dueDate ?? "",
        r.url ?? "",
      ]
        .map(csvField)
        .join(","),
    );
  }
  return `${lines.join("\n")}\n`;
}

export type ParsedContentRow = ContentExportRow;

/** Normalise un nom d'en-tête : minuscules, sans accents. */
function headerKey(h: string): string {
  return h.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().trim();
}

const COLUMNS: Record<string, keyof ParsedContentRow | "secondary"> = {
  titre: "title",
  statut: "status",
  "mot-cle principal": "primaryKeywordTerm",
  "mots-cles secondaires": "secondary",
  langue: "lang",
  pays: "country",
  assigne: "assignee",
  echeance: "dueDate",
  url: "url",
};

export function parseContentRows(cells: string[][]): {
  rows: ParsedContentRow[];
  errors: { line: number; error: string }[];
} {
  if (cells.length === 0) return { rows: [], errors: [] };
  const map = cells[0].map((h) => COLUMNS[headerKey(h)] ?? null);
  const rows: ParsedContentRow[] = [];
  const errors: { line: number; error: string }[] = [];
  for (let i = 1; i < cells.length; i++) {
    const line = i + 1;
    const get = (k: keyof ParsedContentRow | "secondary"): string => {
      const idx = map.indexOf(k);
      return idx >= 0 ? (cells[i][idx] ?? "").trim() : "";
    };
    const title = get("title");
    if (!title) {
      errors.push({ line, error: "Titre requis" });
      continue;
    }
    const statusRaw = get("status");
    const status = (statusRaw || "idea") as ContentStatus;
    if (!STATUSES.includes(status)) {
      errors.push({ line, error: `Statut invalide : ${statusRaw}` });
      continue;
    }
    const dueRaw = get("dueDate");
    if (dueRaw && !/^\d{4}-\d{2}-\d{2}$/.test(dueRaw)) {
      errors.push({
        line,
        error: `Échéance invalide (YYYY-MM-DD) : ${dueRaw}`,
      });
      continue;
    }
    const secondary = get("secondary");
    rows.push({
      title,
      status,
      primaryKeywordTerm: get("primaryKeywordTerm") || null,
      secondaryKeywordTerms: secondary
        ? secondary
            .split("|")
            .map((s) => s.trim())
            .filter(Boolean)
        : [],
      lang: get("lang") || null,
      country: get("country") || null,
      assignee: get("assignee") || null,
      dueDate: dueRaw || null,
      url: get("url") || null,
    });
  }
  return { rows, errors };
}
