/* global React, Icon, window */
// ============================================================================
// MELR · Learning module (Apprentissage) — full prod version
// ----------------------------------------------------------------------------
// The L of MELR : Learning. Captures and structures cross-project learning
// questions, evidence and consolidated insights. Differentiator vs. plain
// "M&E" platforms (most stop at the M+E).
//
// Layout (colored sections to match Reporting style) :
//   - Toolbar (amber)   · scope + period + search + exports
//   - KPIs    (blue)    · total, by state, top tags, projects covered
//   - Questions list (green) · CRUD inline · edit · delete · tag chips
//   - Synthesis (purple) · group by state · by tag · by project · auto-insights
//   - Empty / alerts (red) · questions without recent update, no-tags, etc.
//
// CRUD wired to window.melr.learningQuestionsCrud (Supabase RLS).
// Exports : CSV (📊 green), Word (.docx, 📄 blue), PDF (📕 red, browser print).
// ============================================================================

(function () {
  const { useState, useMemo, useEffect, useRef } = React;

  // ── Constants ───────────────────────────────────────────────────────────
  const STATE_META = {
    active:     { fr: "En instruction", en: "In progress", es: "En instrucción", color: "#2563eb", fill: "#dbeafe" },
    instructed: { fr: "Instruite",      en: "Instructed", es: "Instruida",  color: "#15803d", fill: "#dcfce7" },
    closed:     { fr: "Clôturée",       en: "Closed", es: "Cerrada",      color: "#6b7280", fill: "#f3f4f6" },
  };
  const STATES = ["active", "instructed", "closed"];

  // ── Small UI helpers ────────────────────────────────────────────────────
  function StateBadge({ state, lang }) {
    const m = STATE_META[state] || STATE_META.active;
    return (
      <span style={{
        display: "inline-block", padding: "2px 8px", borderRadius: 10,
        background: m.fill, color: m.color, fontSize: 11, fontWeight: 600,
      }}>{(lang === "es" ? (m.es != null ? m.es : m.en) : lang === "fr" ? m.fr : m.en)}</span>
    );
  }

  function TagChip({ tag, onRemove }) {
    return (
      <span style={{
        display: "inline-flex", alignItems: "center", gap: 4,
        background: "#ede9fe", color: "#6b21a8", padding: "2px 8px",
        borderRadius: 10, fontSize: 11, fontWeight: 500,
      }}>
        #{tag}
        {onRemove && (
          <button onClick={() => onRemove(tag)} title="Supprimer ce tag"
            style={{ background: "none", border: 0, color: "#6b21a8", cursor: "pointer", padding: 0, fontSize: 12, lineHeight: 1 }}>×</button>
        )}
      </span>
    );
  }

  function KpiCard({ label, value, color, hint }) {
    return (
      <div style={{
        background: "var(--bg-elev)", border: "1px solid var(--line)",
        borderRadius: 8, padding: "14px 18px", minWidth: 140, flex: 1,
        boxShadow: "0 1px 2px rgba(0,0,0,.04)",
      }}>
        <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: ".5px", color: "var(--muted)", fontWeight: 600 }}>{label}</div>
        <div style={{ fontSize: 28, fontWeight: 800, color: color || "var(--text)", marginTop: 4 }}>{value}</div>
        {hint && <div style={{ fontSize: 11, color: "var(--muted)", marginTop: 4 }}>{hint}</div>}
      </div>
    );
  }

  function sectionStyle(tintHex, borderHex) {
    return {
      background: tintHex, borderLeft: "4px solid " + borderHex,
      padding: "14px 16px", borderRadius: 8, marginBottom: 16,
    };
  }
  function sectionTitleStyle(color) {
    return { fontSize: 14, fontWeight: 700, margin: "0 0 10px", color, display: "flex", alignItems: "center", gap: 8 };
  }

  // ── Question editor modal ───────────────────────────────────────────────
  // Used for both create and edit. `question` prop = null → create mode.
  function QuestionEditor({ question, projects, lang, onClose, onSaved }) {
    const isNew = !question;
    const [form, setForm] = useState({
      code:       question?.code || "",
      question:   question?.question || question?.t || "",
      project_id: question?.project_id || "",
      state:      question?.state || "active",
      tags:       Array.isArray(question?.tags) ? question.tags : [],
    });
    const [tagInput, setTagInput] = useState("");
    const [busy, setBusy] = useState(false);
    const [error, setError] = useState(null);

    const addTag = () => {
      const t = tagInput.trim();
      if (!t) return;
      if (form.tags.includes(t)) { setTagInput(""); return; }
      setForm({ ...form, tags: [...form.tags, t] });
      setTagInput("");
    };
    const removeTag = (t) => setForm({ ...form, tags: form.tags.filter((x) => x !== t) });

    const submit = async () => {
      if (!form.question.trim()) {
        setError(window.L("La question est obligatoire.", "Question is required.", "La pregunta es obligatoria."));
        return;
      }
      setBusy(true); setError(null);
      try {
        const crud = window.melr && window.melr.learningQuestionsCrud;
        if (!crud) throw new Error(window.L("API indisponible", "API unavailable", "API no disponible"));
        const payload = {
          code:       form.code.trim() || null,
          question:   form.question.trim(),
          project_id: form.project_id || null,
          state:      form.state,
          tags:       form.tags,
        };
        const saved = isNew ? await crud.create(payload) : await crud.update(question.id, payload);
        onSaved && onSaved(saved);
        onClose && onClose();
      } catch (e) {
        setError(e.message);
      } finally {
        setBusy(false);
      }
    };

    return (
      <div style={{
        position: "fixed", inset: 0, background: "rgba(0,0,0,.5)",
        zIndex: 9999, display: "flex", alignItems: "center", justifyContent: "center",
        padding: 20,
      }} onClick={onClose}>
        <div onClick={(e) => e.stopPropagation()} style={{
          background: "var(--bg)", color: "var(--text)", borderRadius: 10,
          width: "min(700px, 100%)", maxHeight: "90vh", overflow: "auto",
          boxShadow: "0 10px 40px rgba(0,0,0,.3)",
        }}>
          <div style={{
            padding: "16px 20px", borderBottom: "1px solid var(--line)",
            display: "flex", alignItems: "center", gap: 10,
          }}>
            <span style={{ fontSize: 20 }}>{isNew ? "✨" : "✏️"}</span>
            <h3 style={{ margin: 0, fontSize: 16, fontWeight: 700 }}>
              {isNew
                ? (window.L("Nouvelle question d'apprentissage", "New learning question", "Nueva pregunta de aprendizaje"))
                : (window.L("Modifier la question", "Edit question", "Editar la pregunta"))}
            </h3>
            <div style={{ flex: 1 }} />
            <button onClick={onClose} style={{ background: "none", border: 0, fontSize: 22, cursor: "pointer", color: "var(--muted)" }}>×</button>
          </div>

          <div style={{ padding: 20 }}>
            {error && (
              <div style={{ padding: 10, marginBottom: 14, background: "#fee2e2", color: "#991b1b", borderRadius: 6, fontSize: 13 }}>
                ⚠️ {error}
              </div>
            )}

            <div style={{ marginBottom: 14 }}>
              <label style={{ display: "block", fontSize: 12, fontWeight: 600, marginBottom: 4, color: "var(--muted)" }}>
                {window.L("Question *", "Question *", "Pregunta *")}
              </label>
              <textarea className="inp" value={form.question}
                onChange={(e) => setForm({ ...form, question: e.target.value })}
                rows={3}
                placeholder={window.L("Ex. Pourquoi l'adoption des moustiquaires chute de 18 % en saison sèche ?", "Ex. Why does ITN adoption drop 18 % in dry season?", "Ej. ¿Por qué la adopción de mosquiteras cae un 18 % en la estación seca?")}
                style={{ width: "100%", fontSize: 14, lineHeight: 1.4 }} />
            </div>

            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12, marginBottom: 14 }}>
              <div>
                <label style={{ display: "block", fontSize: 12, fontWeight: 600, marginBottom: 4, color: "var(--muted)" }}>
                  {window.L("Code (optionnel)", "Code (optional)", "Código (opcional)")}
                </label>
                <input className="inp" value={form.code}
                  onChange={(e) => setForm({ ...form, code: e.target.value })}
                  placeholder="LQ-12" style={{ width: "100%" }} />
              </div>
              <div>
                <label style={{ display: "block", fontSize: 12, fontWeight: 600, marginBottom: 4, color: "var(--muted)" }}>
                  {window.L("Projet *", "Project *", "Proyecto *")}
                </label>
                <select className="inp" value={form.project_id}
                  onChange={(e) => setForm({ ...form, project_id: e.target.value })}
                  style={{ width: "100%" }} required>
                  <option value="">{window.L("— Choisir un projet —", "— Select a project —", "— Elegir un proyecto —")}</option>
                  {(projects || []).map((p) => (
                    <option key={p.uuid || p.id} value={p.uuid || p.id}>
                      {p.id || p.code} — {p.nameFr || p.name_fr || p.name}
                    </option>
                  ))}
                </select>
              </div>
              <div>
                <label style={{ display: "block", fontSize: 12, fontWeight: 600, marginBottom: 4, color: "var(--muted)" }}>
                  {window.L("État", "State", "Estado")}
                </label>
                <select className="inp" value={form.state}
                  onChange={(e) => setForm({ ...form, state: e.target.value })}
                  style={{ width: "100%" }}>
                  {STATES.map((s) => (
                    <option key={s} value={s}>
                      {(lang === "es" ? (STATE_META[s].es != null ? STATE_META[s].es : STATE_META[s].en) : lang === "fr" ? STATE_META[s].fr : STATE_META[s].en)}
                    </option>
                  ))}
                </select>
              </div>
            </div>

            <div style={{ marginBottom: 14 }}>
              <label style={{ display: "block", fontSize: 12, fontWeight: 600, marginBottom: 4, color: "var(--muted)" }}>
                {window.L("Tags", "Tags", "Etiquetas")}
              </label>
              <div style={{ display: "flex", gap: 6, marginBottom: 6, flexWrap: "wrap" }}>
                {form.tags.map((t) => <TagChip key={t} tag={t} onRemove={removeTag} />)}
                {form.tags.length === 0 && (
                  <span style={{ fontSize: 12, fontStyle: "italic", color: "var(--muted)" }}>
                    {window.L("Aucun tag — ajoutez-en ci-dessous", "No tag yet — add some below", "Aún no hay etiquetas — añada algunas abajo")}
                  </span>
                )}
              </div>
              <div style={{ display: "flex", gap: 6 }}>
                <input className="inp" value={tagInput}
                  onChange={(e) => setTagInput(e.target.value)}
                  onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); addTag(); } }}
                  placeholder={window.L("ex. Comportement, ITN, Rétention…", "ex. Behavior, ITN, Retention…", "ej. Comportamiento, ITN, Retención…")}
                  style={{ flex: 1 }} />
                <button onClick={addTag} className="btn sm">+ {window.L("Ajouter", "Add", "Añadir")}</button>
              </div>
            </div>
          </div>

          <div style={{
            padding: "14px 20px", borderTop: "1px solid var(--line)",
            display: "flex", gap: 8, justifyContent: "flex-end",
          }}>
            <button onClick={onClose} className="btn sm ghost" disabled={busy}>
              {window.L("Annuler", "Cancel", "Cancelar")}
            </button>
            <button onClick={submit} disabled={busy} style={{
              padding: "8px 16px", borderRadius: 6, border: 0,
              background: busy ? "#9ca3af" : "#0f766e", color: "white",
              fontWeight: 600, cursor: busy ? "wait" : "pointer",
            }}>
              {busy ? (window.L("Enregistrement…", "Saving…", "Guardando…")) : (window.L("Enregistrer", "Save", "Guardar"))}
            </button>
          </div>
        </div>
      </div>
    );
  }

  // ── Exports ─────────────────────────────────────────────────────────────
  function exportLearningCsv(questions, projects, lang) {
    if (!window.melr || !window.melr.exportCSV) {
      alert(window.L("Export CSV indisponible.", "CSV export unavailable.", "Exportación CSV no disponible."));
      return;
    }
    function projLabel(id) {
      const p = (projects || []).find((x) => (x.uuid || x.id) === id);
      return p ? ((p.id || p.code) + " — " + (p.nameFr || p.name_fr || p.name)) : "";
    }
    const cols = [
      { key: "code",       label: "Code",                                            value: (q) => q.code || q.id },
      { key: "question",   label: window.L("Question", "Question", "Pregunta"),          value: (q) => q.question || q.t || "" },
      { key: "project",    label: window.L("Projet", "Project", "Proyecto"),             value: (q) => projLabel(q.project_id) || "—" },
      { key: "state",      label: window.L("État", "State", "Estado"),                 value: (q) => (lang === "es" ? (STATE_META[q.state]?.es || STATE_META[q.state]?.en) : lang === "fr" ? STATE_META[q.state]?.fr : STATE_META[q.state]?.en) || q.state },
      { key: "owner",      label: window.L("Responsable", "Owner", "Responsable"),          value: (q) => (q.owner && q.owner.full_name) || "—" },
      { key: "tags",       label: "Tags",                                           value: (q) => (q.tags || []).join("; ") },
      { key: "created_at", label: window.L("Date création", "Created at", "Fecha de creación"),   value: (q) => q.created_at ? new Date(q.created_at).toISOString().slice(0, 10) : "" },
    ];
    window.melr.exportCSV("apprentissage-questions.csv", questions, cols);
  }

  async function exportLearningWord(questions, projects, kpis, lang) {
    if (!window.docx) {
      alert(window.L("Bibliothèque Word indisponible.", "Word library unavailable.", "Biblioteca Word no disponible."));
      return;
    }
    const D = window.docx;
    const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, WidthType,
            BorderStyle, ShadingType, AlignmentType, HeadingLevel, Footer, PageNumber } = D;

    const MUTED = "6B7280", LINE = "D1D5DB", PURPLE = "6B21A8";

    function H(level, t) {
      const m = { 1: HeadingLevel.HEADING_1, 2: HeadingLevel.HEADING_2 };
      return new Paragraph({
        heading: m[level], spacing: { before: 280, after: 140 },
        children: [new TextRun({ text: t, bold: true, color: PURPLE })],
      });
    }
    function P(t, opts) {
      opts = opts || {};
      return new Paragraph({
        children: [new TextRun({ text: t == null ? "" : String(t), ...(opts.run || {}) })],
        spacing: { after: 80 },
      });
    }
    function Cell(text, opts) {
      opts = opts || {};
      return new TableCell({
        children: [new Paragraph({
          children: [new TextRun({ text: text == null ? "" : String(text), bold: !!opts.bold, color: opts.color, size: opts.size || 20 })],
          alignment: opts.align,
        })],
        width: opts.width ? { size: opts.width, type: WidthType.DXA } : undefined,
        shading: opts.fill ? { type: ShadingType.CLEAR, color: "auto", fill: opts.fill } : undefined,
        margins: { top: 60, bottom: 60, left: 100, right: 100 },
        borders: {
          top: { style: BorderStyle.SINGLE, size: 4, color: LINE },
          bottom: { style: BorderStyle.SINGLE, size: 4, color: LINE },
          left: { style: BorderStyle.SINGLE, size: 4, color: LINE },
          right: { style: BorderStyle.SINGLE, size: 4, color: LINE },
        },
      });
    }
    function Row(cells) { return new TableRow({ children: cells }); }
    function Tbl(rows, widths) {
      return new Table({
        width: { size: widths.reduce((a, b) => a + b, 0), type: WidthType.DXA },
        columnWidths: widths, rows,
      });
    }
    function projLabel(id) {
      const p = (projects || []).find((x) => (x.uuid || x.id) === id);
      return p ? ((p.id || p.code) + " — " + (p.nameFr || p.name_fr || p.name)) : "—";
    }

    const children = [];

    // Cover
    children.push(new Paragraph({ spacing: { before: 1200 }, children: [] }));
    children.push(new Paragraph({
      alignment: AlignmentType.CENTER,
      children: [new TextRun({ text: window.L("Apprentissage organisationnel", "Organizational Learning", "Aprendizaje organizacional"), bold: true, size: 40, color: PURPLE })],
    }));
    children.push(new Paragraph({
      alignment: AlignmentType.CENTER, spacing: { after: 600 },
      children: [new TextRun({ text: window.L("Questions, instruction, insights consolidés", "Questions, instruction, consolidated insights", "Preguntas, instrucción, insights consolidados"), size: 24, italics: true, color: MUTED })],
    }));
    children.push(new Paragraph({
      alignment: AlignmentType.CENTER, spacing: { after: 1600 },
      children: [new TextRun({ text: (window.L("Document généré le ", "Generated on ", "Documento generado el ")) + new Date().toLocaleDateString(window.L("fr-FR", "en-US", "es-ES")), size: 20, color: MUTED, italics: true })],
    }));

    // KPIs
    children.push(new Paragraph({ children: [new D.PageBreak()] }));
    children.push(H(1, window.L("Indicateurs clés", "Key metrics", "Indicadores clave")));
    const hdr = { fill: PURPLE, color: "FFFFFF", bold: true };
    const kpiRows = [
      Row([Cell(window.L("Métrique", "Metric", "Métrica"), { ...hdr, width: 5000 }), Cell(window.L("Valeur", "Value", "Valor"), { ...hdr, width: 4360, align: AlignmentType.CENTER })]),
      Row([Cell(window.L("Total questions", "Total questions", "Total de preguntas"), { width: 5000 }), Cell(String(kpis.total), { width: 4360, bold: true, align: AlignmentType.CENTER })]),
      Row([Cell(window.L("En instruction (active)", "In progress (active)", "En instrucción (activa)"), { width: 5000 }), Cell(String(kpis.byState.active || 0), { width: 4360, bold: true, color: "2563EB", align: AlignmentType.CENTER })]),
      Row([Cell(window.L("Instruites", "Instructed", "Instruidas"), { width: 5000 }), Cell(String(kpis.byState.instructed || 0), { width: 4360, bold: true, color: "15803D", align: AlignmentType.CENTER })]),
      Row([Cell(window.L("Clôturées", "Closed", "Cerradas"), { width: 5000 }), Cell(String(kpis.byState.closed || 0), { width: 4360, bold: true, color: "6B7280", align: AlignmentType.CENTER })]),
      Row([Cell(window.L("Projets couverts", "Projects covered", "Proyectos cubiertos"), { width: 5000 }), Cell(String(kpis.projectsCovered), { width: 4360, bold: true, align: AlignmentType.CENTER })]),
      Row([Cell(window.L("Tags utilisés", "Tags used", "Etiquetas usadas"), { width: 5000 }), Cell(String(kpis.tagsCount), { width: 4360, bold: true, align: AlignmentType.CENTER })]),
    ];
    children.push(Tbl(kpiRows, [5000, 4360]));

    // Questions detail
    children.push(new Paragraph({ children: [new D.PageBreak()] }));
    children.push(H(1, window.L("Questions d'apprentissage", "Learning questions", "Preguntas de aprendizaje")));
    questions.forEach((q, idx) => {
      if (idx > 0) children.push(new Paragraph({ children: [], spacing: { after: 160 } }));
      children.push(H(2, "[" + (q.code || q.id) + "] " + (q.question || q.t || "")));
      const meta = [
        [window.L("Projet", "Project", "Proyecto"),          projLabel(q.project_id)],
        [window.L("État", "State", "Estado"),              (lang === "es" ? (STATE_META[q.state]?.es || STATE_META[q.state]?.en) : lang === "fr" ? STATE_META[q.state]?.fr : STATE_META[q.state]?.en) || q.state],
        [window.L("Responsable", "Owner", "Responsable"),       (q.owner && q.owner.full_name) || "—"],
        [window.L("Date", "Date", "Fecha"),               q.created_at ? new Date(q.created_at).toLocaleDateString(window.L("fr-FR", "en-US", "es-ES")) : "—"],
        [window.L("Tags", "Tags", "Etiquetas"),               (q.tags || []).map((t) => "#" + t).join(", ") || "—"],
      ];
      const metaRows = meta.map(([k, v]) => Row([
        Cell(k, { width: 2400, bold: true, fill: "F3F4F6", color: PURPLE, size: 18 }),
        Cell(v, { width: 6960, size: 20 }),
      ]));
      children.push(Tbl(metaRows, [2400, 6960]));
    });
    if (questions.length === 0) {
      children.push(P(window.L("Aucune question dans le périmètre.", "No question in scope.", "Ninguna pregunta en el ámbito."), { run: { italics: true, color: MUTED } }));
    }

    const doc = new Document({
      creator: "MELR",
      title: "Learning — " + new Date().toISOString().slice(0, 10),
      styles: { default: { document: { run: { font: "Calibri", size: 22 } } } },
      sections: [{
        properties: { page: { margin: { top: 1200, right: 1200, bottom: 1200, left: 1200 }, size: { width: 11906, height: 16838 } } },
        footers: {
          default: new Footer({
            children: [new Paragraph({
              alignment: AlignmentType.CENTER,
              children: [
                new TextRun({ text: (window.L("MELR · Apprentissage · ", "MELR · Learning · ", "MELR · Aprendizaje · ")), color: MUTED, size: 18 }),
                new TextRun({ children: [PageNumber.CURRENT], color: MUTED, size: 18 }),
                new TextRun({ text: " / ", color: MUTED, size: 18 }),
                new TextRun({ children: [PageNumber.TOTAL_PAGES], color: MUTED, size: 18 }),
              ],
            })],
          }),
        },
        children,
      }],
    });
    try {
      const blob = await Packer.toBlob(doc);
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url; a.download = "apprentissage-questions.docx";
      document.body.appendChild(a); a.click(); a.remove();
      setTimeout(() => URL.revokeObjectURL(url), 4000);
    } catch (e) {
      console.error("[learning] export Word:", e);
      alert((window.L("Erreur export Word : ", "Word export error: ", "Error de exportación a Word: ")) + e.message);
    }
  }

  function exportLearningPdf() {
    document.documentElement.classList.add("melr-print-learning");
    setTimeout(() => {
      try { window.print(); } finally {
        setTimeout(() => document.documentElement.classList.remove("melr-print-learning"), 500);
      }
    }, 50);
  }

  // ── Main Learning component ────────────────────────────────────────────
  function Learning({ t, lang }) {
    const { data: liveQ, refresh } = window.melr.useLearningQuestions
      ? window.melr.useLearningQuestions()
      : { data: [], refresh: () => {} };
    const { projects = [] } = window.melr.useProjects ? window.melr.useProjects() : { projects: [] };

    // Local filter state
    const [search, setSearch] = useState("");
    const [projectFilter, setProjectFilter] = useState("");
    const [stateFilter, setStateFilter]     = useState("");
    const [tagFilter, setTagFilter]         = useState("");

    // Editor modal state
    const [editorOpen, setEditorOpen]   = useState(false);
    const [editingQ, setEditingQ]       = useState(null);  // null = create

    // Normalise live data (which uses `question` not `t`, `owner.full_name`)
    const questions = useMemo(() => liveQ || [], [liveQ]);

    // Collect all tags for filter dropdown
    const allTags = useMemo(() => {
      const s = new Set();
      questions.forEach((q) => (q.tags || []).forEach((t) => s.add(t)));
      return Array.from(s).sort();
    }, [questions]);

    // Filtered list
    const filtered = useMemo(() => {
      const s = search.trim().toLowerCase();
      return questions.filter((q) => {
        if (projectFilter && q.project_id !== projectFilter) return false;
        if (stateFilter && q.state !== stateFilter) return false;
        if (tagFilter && !(q.tags || []).includes(tagFilter)) return false;
        if (s) {
          const hay = (q.question || "") + " " + (q.code || "") + " " + (q.tags || []).join(" ");
          if (!hay.toLowerCase().includes(s)) return false;
        }
        return true;
      });
    }, [questions, search, projectFilter, stateFilter, tagFilter]);

    // KPIs computed on the FILTERED set so the cards react to filter changes
    const kpis = useMemo(() => {
      const byState = {};
      const byTag = new Map();
      const byProject = new Set();
      filtered.forEach((q) => {
        byState[q.state] = (byState[q.state] || 0) + 1;
        (q.tags || []).forEach((t) => byTag.set(t, (byTag.get(t) || 0) + 1));
        if (q.project_id) byProject.add(q.project_id);
      });
      const topTags = Array.from(byTag.entries()).sort((a, b) => b[1] - a[1]).slice(0, 6);
      return {
        total: filtered.length,
        byState,
        topTags,
        projectsCovered: byProject.size,
        tagsCount: byTag.size,
      };
    }, [filtered]);

    // Auto-insights from the synthesis section
    const insights = useMemo(() => {
      const out = [];
      // Most-active tag
      if (kpis.topTags.length > 0) {
        const [t, c] = kpis.topTags[0];
        out.push({
          kind: "info",
          message: (window.L("Le tag le plus fréquent est ", "Most frequent tag is ", "La etiqueta más frecuente es ")) +
            "#" + t + " (" + c + " " + (window.L("questions", "questions", "preguntas")) + ")",
        });
      }
      // Closed / total ratio
      if (kpis.total > 0) {
        const closed = kpis.byState.closed || 0;
        const ratio = Math.round((closed / kpis.total) * 100);
        out.push({
          kind: closed > kpis.total * 0.5 ? "ok" : "info",
          message: (window.L("Taux de clôture : ", "Closure rate: ", "Tasa de cierre: ")) + ratio + " % (" + closed + "/" + kpis.total + ")",
        });
      }
      // Questions without tags
      const untagged = filtered.filter((q) => !q.tags || q.tags.length === 0);
      if (untagged.length > 0) {
        out.push({
          kind: "warn",
          message: (window.L("Questions sans tag : ", "Untagged questions: ", "Preguntas sin etiqueta: ")) + untagged.length + " (" + (window.L("à catégoriser pour analyse trans-projets", "categorize for cross-project analysis", "categorizar para el análisis transversal entre proyectos")) + ")",
        });
      }
      // Old active questions (> 90 days, not closed)
      const ninetyDaysAgo = Date.now() - 90 * 24 * 3600 * 1000;
      const stale = filtered.filter((q) => q.state === "active" && q.created_at && new Date(q.created_at).getTime() < ninetyDaysAgo);
      if (stale.length > 0) {
        out.push({
          kind: "warn",
          message: (window.L("Questions actives anciennes (> 90 jours) : ", "Stale active questions (> 90 days): ", "Preguntas activas antiguas (> 90 días): ")) + stale.length,
        });
      }
      return out;
    }, [kpis, filtered, lang]);

    // Group breakdown for synthesis
    const groupByProject = useMemo(() => {
      const m = new Map();
      filtered.forEach((q) => {
        const k = q.project_id || "__none__";
        if (!m.has(k)) m.set(k, []);
        m.get(k).push(q);
      });
      return Array.from(m.entries()).sort((a, b) => b[1].length - a[1].length);
    }, [filtered]);

    function projectLabel(id) {
      if (!id || id === "__none__") return window.L("(Non rattachées)", "(Unassigned)", "(Sin asignar)");
      const p = projects.find((x) => (x.uuid || x.id) === id);
      return p ? ((p.id || p.code) + " — " + (p.nameFr || p.name_fr || p.name)) : id;
    }

    // CRUD handlers
    const handleDelete = async (q) => {
      if (!window.confirm((window.L("Supprimer la question ", "Delete question ", "Eliminar la pregunta ")) + (q.code || q.id) + " ?")) return;
      try {
        await window.melr.learningQuestionsCrud.remove(q.id);
        refresh && refresh();
      } catch (e) {
        alert((window.L("Erreur suppression : ", "Delete error: ", "Error de eliminación: ")) + e.message);
      }
    };
    const handleEdit = (q) => { setEditingQ(q); setEditorOpen(true); };
    const handleNew  = ()  => { setEditingQ(null); setEditorOpen(true); };
    const handleSaved = ()  => { refresh && refresh(); };

    return (
      <div className="page" id="melr-learning-printable">
        <style>{`
          @media print {
            html.melr-print-learning body * { visibility: hidden !important; }
            html.melr-print-learning #melr-learning-printable,
            html.melr-print-learning #melr-learning-printable * { visibility: visible !important; }
            html.melr-print-learning #melr-learning-printable {
              position: absolute !important; left: 0; top: 0; width: 100% !important;
              padding: 12px !important;
            }
            html.melr-print-learning .melr-learning-noprint { display: none !important; }
          }
        `}</style>

        <div className="page-header">
          <div className="page-eyebrow">{window.L("APPRENTISSAGE / QUESTIONS", "LEARNING / QUESTIONS", "APRENDIZAJE / PREGUNTAS")}</div>
          <div className="page-header-row">
            <div>
              <h1 className="page-title">{window.L("Questions d'Apprentissage", "Learning questions", "Preguntas de aprendizaje")}</h1>
              <div className="page-sub">{window.L("Questions instruites par projet · base d'évidence structurée · synthèse trans-projets — le L de MELR.", "Learning questions instructed per project · structured evidence base · cross-project synthesis — the L of MELR.", "Preguntas instruidas por proyecto · base de evidencia estructurada · síntesis transversal entre proyectos — la L de MELR.")}</div>
            </div>
            <div className="page-header-actions">
              <button onClick={handleNew} style={{
                padding: "8px 14px", borderRadius: 6, border: 0,
                background: "#1d4ed8", color: "white", cursor: "pointer", fontWeight: 600,
              }}>
                <Icon.plus /> {window.L("Nouvelle question", "New question", "Nueva pregunta")}
              </button>
            </div>
          </div>
        </div>

        <div className="page-body">
          {/* ===== Filtres + Exports (amber) ===== */}
          <div className="melr-learning-noprint" style={sectionStyle("rgba(245, 158, 11, 0.06)", "#f59e0b")}>
            <div style={sectionTitleStyle("#92400e")}>
              <span>⚙️</span><span>{window.L("Filtres & exports", "Filters & exports", "Filtros y exportaciones")}</span>
            </div>
            <div style={{ display: "flex", gap: 10, flexWrap: "wrap", alignItems: "flex-end" }}>
              <div style={{ flex: "0 0 220px" }}>
                <label style={{ display: "block", fontSize: 11, fontWeight: 600, color: "var(--muted)", marginBottom: 3 }}>{window.L("Recherche", "Search", "Búsqueda")}</label>
                <input className="inp sm" value={search} onChange={(e) => setSearch(e.target.value)}
                  placeholder={window.L("Mot-clé, code, tag…", "Keyword, code, tag…", "Palabra clave, código, etiqueta…")}
                  style={{ width: "100%" }} />
              </div>
              <div>
                <label style={{ display: "block", fontSize: 11, fontWeight: 600, color: "var(--muted)", marginBottom: 3 }}>{window.L("Projet", "Project", "Proyecto")}</label>
                <select className="inp sm" value={projectFilter} onChange={(e) => setProjectFilter(e.target.value)}>
                  <option value="">{window.L("Tous", "All", "Todos")}</option>
                  {projects.map((p) => (
                    <option key={p.uuid || p.id} value={p.uuid || p.id}>{p.id || p.code}</option>
                  ))}
                </select>
              </div>
              <div>
                <label style={{ display: "block", fontSize: 11, fontWeight: 600, color: "var(--muted)", marginBottom: 3 }}>{window.L("État", "State", "Estado")}</label>
                <select className="inp sm" value={stateFilter} onChange={(e) => setStateFilter(e.target.value)}>
                  <option value="">{window.L("Tous", "All", "Todos")}</option>
                  {STATES.map((s) => (
                    <option key={s} value={s}>{(lang === "es" ? (STATE_META[s].es != null ? STATE_META[s].es : STATE_META[s].en) : lang === "fr" ? STATE_META[s].fr : STATE_META[s].en)}</option>
                  ))}
                </select>
              </div>
              <div>
                <label style={{ display: "block", fontSize: 11, fontWeight: 600, color: "var(--muted)", marginBottom: 3 }}>Tag</label>
                <select className="inp sm" value={tagFilter} onChange={(e) => setTagFilter(e.target.value)}>
                  <option value="">{window.L("Tous", "All", "Todos")}</option>
                  {allTags.map((tag) => <option key={tag} value={tag}>#{tag}</option>)}
                </select>
              </div>
              <div style={{ flex: 1 }} />
              <button onClick={() => exportLearningCsv(filtered, projects, lang)}
                disabled={filtered.length === 0}
                title={window.L("Export CSV (Excel)", "Export CSV (Excel)", "Exportar CSV (Excel)")}
                style={{ padding: "6px 12px", borderRadius: 6, border: "1px solid #16a34a", background: "#16a34a", color: "white", cursor: filtered.length === 0 ? "not-allowed" : "pointer", fontSize: 12.5, fontWeight: 600, opacity: filtered.length === 0 ? 0.5 : 1 }}>
                📊 CSV
              </button>
              <button onClick={() => exportLearningWord(filtered, projects, kpis, lang)}
                disabled={filtered.length === 0 || !window.docx}
                title={window.L("Export Word (.docx)", "Export Word (.docx)", "Exportar Word (.docx)")}
                style={{ padding: "6px 12px", borderRadius: 6, border: "1px solid #2563eb", background: "#2563eb", color: "white", cursor: (filtered.length === 0 || !window.docx) ? "not-allowed" : "pointer", fontSize: 12.5, fontWeight: 600, opacity: (filtered.length === 0 || !window.docx) ? 0.5 : 1 }}>
                📄 Word
              </button>
              <button onClick={exportLearningPdf}
                disabled={filtered.length === 0}
                title={window.L("Imprimer / PDF", "Print / PDF", "Imprimir / PDF")}
                style={{ padding: "6px 12px", borderRadius: 6, border: "1px solid #dc2626", background: "#dc2626", color: "white", cursor: filtered.length === 0 ? "not-allowed" : "pointer", fontSize: 12.5, fontWeight: 600, opacity: filtered.length === 0 ? 0.5 : 1 }}>
                📕 PDF
              </button>
            </div>
          </div>

          {/* ===== KPIs (blue) ===== */}
          <div style={sectionStyle("rgba(59, 130, 246, 0.06)", "#3b82f6")}>
            <div style={sectionTitleStyle("#1e40af")}>
              <span>📊</span><span>{window.L("Indicateurs clés du module", "Module key metrics", "Indicadores clave del módulo")}</span>
            </div>
            <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
              <KpiCard label={window.L("Questions", "Questions", "Preguntas")} value={kpis.total} />
              <KpiCard label={window.L("En instruction", "In progress", "En instrucción")} value={kpis.byState.active || 0} color="#2563eb" />
              <KpiCard label={window.L("Instruites", "Instructed", "Instruidas")} value={kpis.byState.instructed || 0} color="#15803d" />
              <KpiCard label={window.L("Clôturées", "Closed", "Cerradas")} value={kpis.byState.closed || 0} color="#6b7280" />
              <KpiCard label={window.L("Projets couverts", "Projects covered", "Proyectos cubiertos")} value={kpis.projectsCovered} />
              <KpiCard label="Tags" value={kpis.tagsCount} />
            </div>
          </div>

          {/* ===== Questions list (green) ===== */}
          <div style={sectionStyle("rgba(16, 185, 129, 0.06)", "#10b981")}>
            <div style={sectionTitleStyle("#065f46")}>
              <span>📝</span>
              <span>{window.L("Questions d'apprentissage", "Learning questions", "Preguntas de aprendizaje")}</span>
              <span style={{ marginLeft: "auto", fontSize: 11, color: "var(--muted)", fontWeight: 500 }}>
                ({filtered.length})
              </span>
            </div>
            {filtered.length === 0 ? (
              <div style={{
                padding: 30, background: "var(--bg-elev)", borderRadius: 8,
                border: "1px dashed var(--line)", textAlign: "center",
                color: "var(--muted)", fontStyle: "italic", fontSize: 13,
              }}>
                {questions.length === 0
                  ? (window.L("Aucune question dans cette organisation. Cliquez sur « Nouvelle question » pour en créer une.", "No questions in this organization. Click 'New question' to create one.", "Ninguna pregunta en esta organización. Haga clic en «Nueva pregunta» para crear una."))
                  : (window.L("Aucune question ne correspond aux filtres.", "No question matches the filters.", "Ninguna pregunta coincide con los filtros."))}
              </div>
            ) : (
              <div style={{ background: "var(--bg-elev)", border: "1px solid var(--line)", borderRadius: 8 }}>
                {filtered.map((q, idx) => (
                  <div key={q.id} style={{
                    padding: "14px 16px",
                    borderBottom: idx === filtered.length - 1 ? "none" : "1px solid var(--line)",
                  }}>
                    <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 6, flexWrap: "wrap" }}>
                      <span className="tag-mono">{q.code || q.id}</span>
                      {q.projects && q.projects.code && <span className="tag-mono">{q.projects.code}</span>}
                      <StateBadge state={q.state} lang={lang} />
                      <div style={{ flex: 1 }} />
                      <span style={{ fontSize: 11, color: "var(--muted)" }}>
                        {q.created_at ? new Date(q.created_at).toLocaleDateString(window.L("fr-FR", "en-US", "es-ES")) : ""}
                      </span>
                      <button onClick={() => handleEdit(q)} className="btn xs ghost" title={window.L("Modifier", "Edit", "Editar")}>
                        ✏️ {window.L("Modifier", "Edit", "Editar")}
                      </button>
                      <button onClick={() => handleDelete(q)} className="btn xs ghost" title={window.L("Supprimer", "Delete", "Eliminar")}
                        style={{ color: "#dc2626" }}>
                        🗑
                      </button>
                    </div>
                    <div style={{ fontWeight: 500, fontSize: 13.5, marginBottom: 6, lineHeight: 1.4 }}>{q.question}</div>
                    <div style={{ display: "flex", gap: 6, alignItems: "center", flexWrap: "wrap", fontSize: 11.5, color: "var(--muted)" }}>
                      <span><Icon.user /> {(q.owner && q.owner.full_name) || (window.L("Non assigné", "Unassigned", "Sin asignar"))}</span>
                      <span style={{ flex: 1 }} />
                      {(q.tags || []).map((tag) => <TagChip key={tag} tag={tag} />)}
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>

          {/* ===== Cross-project synthesis (purple) ===== */}
          <div style={sectionStyle("rgba(168, 85, 247, 0.06)", "#a855f7")}>
            <div style={sectionTitleStyle("#6b21a8")}>
              <span>🧠</span>
              <span>{window.L("Synthèse trans-projets", "Cross-project synthesis", "Síntesis transversal entre proyectos")}</span>
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
              <div style={{ background: "var(--bg-elev)", border: "1px solid var(--line)", borderRadius: 8, padding: 14 }}>
                <h4 style={{ margin: "0 0 8px", fontSize: 12, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: ".5px" }}>
                  {window.L("Top tags", "Top tags", "Etiquetas principales")}
                </h4>
                {kpis.topTags.length === 0 ? (
                  <div style={{ fontSize: 12, color: "var(--muted)", fontStyle: "italic" }}>
                    {window.L("Aucun tag.", "No tag yet.", "Aún no hay etiquetas.")}
                  </div>
                ) : (
                  <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
                    {kpis.topTags.map(([tag, count]) => (
                      <div key={tag} style={{ display: "flex", alignItems: "center", gap: 8 }}>
                        <TagChip tag={tag} />
                        <div style={{
                          flex: 1, height: 6, background: "var(--bg)", borderRadius: 3, overflow: "hidden", position: "relative",
                        }}>
                          <div style={{
                            position: "absolute", top: 0, left: 0, bottom: 0,
                            width: ((count / kpis.topTags[0][1]) * 100) + "%",
                            background: "#a855f7", borderRadius: 3,
                          }} />
                        </div>
                        <span style={{ fontSize: 11, color: "var(--muted)", minWidth: 28, textAlign: "right" }}>{count}</span>
                      </div>
                    ))}
                  </div>
                )}
              </div>

              <div style={{ background: "var(--bg-elev)", border: "1px solid var(--line)", borderRadius: 8, padding: 14 }}>
                <h4 style={{ margin: "0 0 8px", fontSize: 12, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: ".5px" }}>
                  {window.L("Par projet", "By project", "Por proyecto")}
                </h4>
                {groupByProject.length === 0 ? (
                  <div style={{ fontSize: 12, color: "var(--muted)", fontStyle: "italic" }}>
                    {window.L("Aucune question.", "No questions.", "Ninguna pregunta.")}
                  </div>
                ) : (
                  <div style={{ display: "flex", flexDirection: "column", gap: 6, maxHeight: 220, overflowY: "auto" }}>
                    {groupByProject.slice(0, 8).map(([pid, qs]) => (
                      <div key={pid} style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 12 }}>
                        <span style={{ flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }} title={projectLabel(pid)}>
                          {projectLabel(pid)}
                        </span>
                        <span className="pill" style={{ fontSize: 11 }}>{qs.length}</span>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            </div>

            {insights.length > 0 && (
              <div style={{ marginTop: 12 }}>
                <h4 style={{ margin: "0 0 8px", fontSize: 12, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: ".5px" }}>
                  {window.L("Insights automatiques", "Auto-insights", "Insights automáticos")}
                </h4>
                <div style={{ background: "var(--bg-elev)", border: "1px solid var(--line)", borderRadius: 8 }}>
                  {insights.map((ins, i) => (
                    <div key={i} style={{
                      padding: "8px 12px",
                      borderBottom: i === insights.length - 1 ? "none" : "1px solid var(--line)",
                      fontSize: 12.5, display: "flex", gap: 8,
                    }}>
                      <span>{ins.kind === "ok" ? "✅" : ins.kind === "warn" ? "🟡" : "ℹ️"}</span>
                      <span>{ins.message}</span>
                    </div>
                  ))}
                </div>
              </div>
            )}
          </div>
        </div>

        {/* Editor modal */}
        {editorOpen && (
          <QuestionEditor
            question={editingQ}
            projects={projects}
            lang={lang}
            onClose={() => setEditorOpen(false)}
            onSaved={handleSaved}
          />
        )}
      </div>
    );
  }

  window.Learning = Learning;
})();
