import { Router } from 'express';
import { z } from 'zod';
import multer from 'multer';
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
import sharp from 'sharp';
import db from '../db/index.js';
import { createZip, readZip } from '../utils/zip.js';
import { HttpError } from '../middleware/errorHandler.js';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const dataDir   = process.env.DATA_DIR
  ? path.resolve(process.env.DATA_DIR)
  : path.resolve(__dirname, '../../../data'); // fallback dev : 3 niveaux au-dessus de routes/
const logosDir  = path.join(dataDir, 'logos');
fs.mkdirSync(logosDir, { recursive: true });

// ── Traitement image (réutilisé depuis plateformes.js) ─────────────────────

async function processLogoFile(filePath) {
  const ext = path.extname(filePath).toLowerCase();
  if (ext === '.svg') {
    try {
      let svg = fs.readFileSync(filePath, 'utf8');
      // Supprimer fond blanc SVG (background-color, rect blanc, etc.)
      svg = svg.replace(/(<svg\b[^>]*)\sstyle="([^"]*)"/i, (_, tag, style) => {
        const cleaned = style.split(';').filter(s => !/^\s*background(-color)?\s*:/i.test(s)).join(';').replace(/^;+|;+$/g, '');
        return cleaned ? `${tag} style="${cleaned}"` : tag;
      });
      svg = svg.replace(/\s+enable-background="[^"]*"/gi, '');
      fs.writeFileSync(filePath, svg, 'utf8');
    } catch (e) { console.warn('[ref-logos] SVG cleanup failed:', e.message); }
    return filePath;
  }
  if (['.png', '.jpg', '.jpeg', '.webp'].includes(ext)) {
    const pngPath = filePath.replace(/\.(jpg|jpeg|webp|png)$/i, '.png');
    try {
      const { data, info } = await sharp(filePath).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
      for (let i = 0; i < data.length; i += 4) {
        if (data[i] > 240 && data[i + 1] > 240 && data[i + 2] > 240) data[i + 3] = 0;
      }
      await sharp(data, { raw: { width: info.width, height: info.height, channels: 4 } })
        .png({ compressionLevel: 8 }).toFile(pngPath);
      if (pngPath !== filePath) fs.unlinkSync(filePath);
      return pngPath;
    } catch (e) { console.warn('[ref-logos] sharp failed:', e.message); return filePath; }
  }
  return filePath;
}

// ── Multer ──────────────────────────────────────────────────────────────────
const storage = multer.diskStorage({
  destination: (_req, _file, cb) => cb(null, logosDir),
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname).toLowerCase() || '.png';
    cb(null, `ref_${req.params.id}_${Date.now()}${ext}`);
  },
});
const upload = multer({
  storage,
  limits: { fileSize: 2 * 1024 * 1024 },
  fileFilter: (_req, file, cb) => {
    const allowed = ['.svg', '.png', '.jpg', '.jpeg', '.webp'];
    if (allowed.includes(path.extname(file.originalname).toLowerCase())) cb(null, true);
    else cb(new Error('Format non supporté — SVG, PNG, JPG ou WebP uniquement'));
  },
});

const router = Router();
// Toutes ces routes sont montées sous requireAdmin dans server.js

const Schema = z.object({
  nom:                   z.string().min(1).max(200),
  url:                   z.string().url().optional().or(z.literal('')).nullable(),
  domiciliation:         z.string().min(1).max(100).default('france'),
  fiscalite:             z.enum(['flat_tax', 'sans_fiscalite_locale', 'avec_fiscalite_locale']).default('flat_tax'),
  taux_fiscalite_locale: z.number().min(0).max(100).nullable().optional(),
  type_produit_fiscal:   z.enum(['2TT', '2TR']).default('2TT'),
  methode_remboursement: z.enum(['portefeuille', 'compte_courant', 'choix_investisseur']).optional().default('portefeuille'),
  type_pret_defaut:      z.enum(['in_fine', 'amortissable', 'differe']).nullable().optional(),
  freq_interets_defaut:  z.enum(['mensuel', 'trimestriel', 'in_fine']).nullable().optional(),
  logo_filename:         z.string().nullable().optional(),
  description:           z.string().nullable().optional(),
  // Profil enrichi
  annee_creation:         z.number().int().nullable().optional(),
  investisseurs_types:    z.string().nullable().optional(),
  regulateur:             z.string().nullable().optional(),
  numero_licence:         z.string().nullable().optional(),
  is_regule:              z.union([z.boolean(), z.number()]).optional().default(false),
  pays_inscription:       z.string().nullable().optional(),
  pays_siege:             z.string().nullable().optional(),
  pays_operation:         z.array(z.string()).optional().default([]),
  investissement_minimum: z.number().nullable().optional(),
  rendement_annonce:      z.number().nullable().optional(),
  nb_investisseurs:       z.number().int().nullable().optional(),
  volume_total_finance:   z.number().nullable().optional(),
  duree_moyenne_pret:     z.number().nullable().optional(),
  garantie_rachat:        z.union([z.boolean(), z.number()]).optional().default(false),
  statistiques_publiques: z.union([z.boolean(), z.number()]).optional().default(false),
  bonus_inscription:      z.union([z.boolean(), z.number()]).optional().default(false),
  marche_secondaire:      z.union([z.boolean(), z.number()]).optional().default(false),
  investissement_auto:    z.union([z.boolean(), z.number()]).optional().default(false),
  url_trustpilot:         z.string().url().optional().or(z.literal('')).nullable(),
  url_linkedin:           z.string().url().optional().or(z.literal('')).nullable(),
  // Catégories : tableau de noms (strings) — indépendant des catégories user (legacy)
  categories:            z.array(z.string().min(1)).optional().default([]),
  // Nouvelles listes gérées globalement (IDs)
  categories_inv_ids:    z.array(z.number().int()).optional().default([]),
  secteurs_inv_ids:      z.array(z.number().int()).optional().default([]),
  // Notation : tableau de critères
  notation:              z.array(z.object({
    nom:         z.string().min(1),
    type:        z.enum(['etoiles', 'lettres', 'score', 'custom']).default('etoiles'),
    valeurs:     z.array(z.string()).nullable().optional(),
    min_val:     z.number().nullable().optional(),
    max_val:     z.number().nullable().optional(),
    description: z.string().nullable().optional(),
    ordre:       z.number().int().default(0),
  })).optional().default([]),
});

// ── Helpers ────────────────────────────────────────────────────────────────

/** Catégories attachées au référentiel (stockées comme strings dans referentiel_categories.nom) */
function attachCats(rows) {
  if (rows.length === 0) return rows;
  const ids = rows.map(r => r.id);
  const cats = db.prepare(`
    SELECT rc.referentiel_id, rc.categorie_nom
    FROM referentiel_categories rc
    WHERE rc.referentiel_id IN (${ids.map(() => '?').join(',')})
    ORDER BY rc.categorie_nom
  `).all(...ids);

  const map = {};
  for (const c of cats) {
    if (!map[c.referentiel_id]) map[c.referentiel_id] = [];
    map[c.referentiel_id].push(c.categorie_nom);
  }
  return rows.map(r => ({ ...r, categories: map[r.id] || [] }));
}

/** Catégories d'investissement globales (categories_inv) */
function attachCatsInv(rows) {
  if (rows.length === 0) return rows;
  const ids = rows.map(r => r.id);
  const links = db.prepare(`
    SELECT rc.referentiel_id, c.id AS categorie_id, c.nom
    FROM referentiel_categories_inv rc
    JOIN categories_inv c ON c.id = rc.categorie_id
    WHERE rc.referentiel_id IN (${ids.map(() => '?').join(',')})
    ORDER BY c.nom
  `).all(...ids);
  const map = {};
  for (const l of links) {
    if (!map[l.referentiel_id]) map[l.referentiel_id] = [];
    map[l.referentiel_id].push({ id: l.categorie_id, nom: l.nom });
  }
  return rows.map(r => ({ ...r, categories_inv: map[r.id] || [] }));
}

/** Secteurs d'investissement globaux (secteurs_inv) */
function attachSecteursInv(rows) {
  if (rows.length === 0) return rows;
  const ids = rows.map(r => r.id);
  const links = db.prepare(`
    SELECT rs.referentiel_id, s.id AS secteur_id, s.nom
    FROM referentiel_secteurs_inv rs
    JOIN secteurs_inv s ON s.id = rs.secteur_id
    WHERE rs.referentiel_id IN (${ids.map(() => '?').join(',')})
    ORDER BY s.nom
  `).all(...ids);
  const map = {};
  for (const l of links) {
    if (!map[l.referentiel_id]) map[l.referentiel_id] = [];
    map[l.referentiel_id].push({ id: l.secteur_id, nom: l.nom });
  }
  return rows.map(r => ({ ...r, secteurs_inv: map[r.id] || [] }));
}

/** Critères de notation du référentiel */
function attachNotation(rows) {
  if (rows.length === 0) return rows;
  const ids = rows.map(r => r.id);
  const notations = db.prepare(`
    SELECT * FROM referentiel_notation
    WHERE referentiel_id IN (${ids.map(() => '?').join(',')})
    ORDER BY referentiel_id, ordre, id
  `).all(...ids);

  const map = {};
  for (const n of notations) {
    if (!map[n.referentiel_id]) map[n.referentiel_id] = [];
    map[n.referentiel_id].push({
      ...n,
      valeurs: n.valeurs ? JSON.parse(n.valeurs) : null,
    });
  }
  return rows.map(r => ({ ...r, notation: map[r.id] || [] }));
}

/** Parse pays_operation (JSON TEXT → array) */
function parsePaysOp(rows) {
  return rows.map(r => ({
    ...r,
    pays_operation: r.pays_operation
      ? (typeof r.pays_operation === 'string' ? JSON.parse(r.pays_operation) : r.pays_operation)
      : [],
  }));
}

/** Enregistre catégories, secteurs et notation pour un référentiel */
function saveRelations(tx, refId, categories, notation, categoriesInvIds, secteursInvIds) {
  tx(() => {
    // Legacy string categories
    db.prepare('DELETE FROM referentiel_categories WHERE referentiel_id = ?').run(refId);
    if (categories.length > 0) {
      const ins = db.prepare(
        'INSERT OR IGNORE INTO referentiel_categories (referentiel_id, categorie_nom) VALUES (?, ?)'
      );
      for (const nom of categories) ins.run(refId, nom.trim());
    }

    // Nouvelles catégories globales (IDs)
    db.prepare('DELETE FROM referentiel_categories_inv WHERE referentiel_id = ?').run(refId);
    if (categoriesInvIds && categoriesInvIds.length > 0) {
      const ins = db.prepare('INSERT OR IGNORE INTO referentiel_categories_inv (referentiel_id, categorie_id) VALUES (?,?)');
      for (const id of categoriesInvIds) ins.run(refId, id);
    }

    // Secteurs globaux (IDs)
    db.prepare('DELETE FROM referentiel_secteurs_inv WHERE referentiel_id = ?').run(refId);
    if (secteursInvIds && secteursInvIds.length > 0) {
      const ins = db.prepare('INSERT OR IGNORE INTO referentiel_secteurs_inv (referentiel_id, secteur_id) VALUES (?,?)');
      for (const id of secteursInvIds) ins.run(refId, id);
    }

    db.prepare('DELETE FROM referentiel_notation WHERE referentiel_id = ?').run(refId);
    if (notation.length > 0) {
      const ins = db.prepare(`
        INSERT INTO referentiel_notation (referentiel_id, nom, type, valeurs, min_val, max_val, description, ordre)
        VALUES (?,?,?,?,?,?,?,?)
      `);
      for (const n of notation) {
        ins.run(
          refId, n.nom, n.type || 'etoiles',
          (n.valeurs && n.valeurs.length) ? JSON.stringify(n.valeurs) : null,
          n.min_val ?? null, n.max_val ?? null,
          n.description ?? null, n.ordre ?? 0
        );
      }
    }
  });
}

// ── GET /api/referentiel ───────────────────────────────────────────────────
router.get('/', (_req, res) => {
  let rows = db.prepare(`
    SELECT pr.*,
           (SELECT COUNT(*) FROM plateformes p WHERE p.referentiel_id = pr.id) AS nb_plateformes_liees
    FROM plateformes_referentiel pr
    ORDER BY pr.nom
  `).all();
  rows = attachCats(rows);
  rows = attachCatsInv(rows);
  rows = attachSecteursInv(rows);
  rows = attachNotation(rows);
  rows = parsePaysOp(rows);
  res.json(rows);
});

// ── Multer for ZIP uploads ─────────────────────────────────────────────────
const zipUpload = multer({
  storage: multer.memoryStorage(),
  limits: { fileSize: 50 * 1024 * 1024 },
  fileFilter: (_req, file, cb) => {
    if (file.mimetype === 'application/zip' || file.originalname.endsWith('.zip')) cb(null, true);
    else cb(new HttpError(400, 'Fichier ZIP attendu'));
  },
});

// ── GET /api/referentiel/export — export tout le référentiel ───────────────
router.get('/export', (req, res, next) => {
  try {
    let rows = db.prepare('SELECT * FROM plateformes_referentiel ORDER BY nom').all();
    rows = attachCatsInv(rows);
    rows = attachSecteursInv(rows);
    rows = parsePaysOp(rows);

    const entries = [];
    const manifest = {
      version: '1.1',
      app: 'crowdlending',
      exported_at: new Date().toISOString(),
      count: rows.length,
      type: 'referentiel',
    };
    entries.push({ name: 'manifest.json', data: JSON.stringify(manifest, null, 2) });

    // Attach referentiel_notation to each platform
    const notationByRef = {};
    const notRows = db.prepare('SELECT * FROM referentiel_notation ORDER BY referentiel_id, ordre, id').all();
    for (const n of notRows) {
      if (!notationByRef[n.referentiel_id]) notationByRef[n.referentiel_id] = [];
      notationByRef[n.referentiel_id].push({
        nom: n.nom,
        type: n.type,
        valeurs: n.valeurs ? JSON.parse(n.valeurs) : null,
        min_val: n.min_val,
        max_val: n.max_val,
        description: n.description,
        ordre: n.ordre,
      });
    }

    const dataRows = rows.map(r => ({
      nom: r.nom,
      url: r.url,
      domiciliation: r.domiciliation,
      fiscalite: r.fiscalite,
      taux_fiscalite_locale: r.taux_fiscalite_locale,
      type_produit_fiscal: r.type_produit_fiscal,
      description: r.description,
      annee_creation: r.annee_creation,
      investisseurs_types: r.investisseurs_types,
      regulateur: r.regulateur,
      numero_licence: r.numero_licence,
      is_regule: r.is_regule,
      pays_inscription: r.pays_inscription,
      pays_siege: r.pays_siege,
      pays_operation: r.pays_operation || [],
      investissement_minimum: r.investissement_minimum,
      rendement_annonce: r.rendement_annonce,
      nb_investisseurs: r.nb_investisseurs,
      volume_total_finance: r.volume_total_finance,
      duree_moyenne_pret: r.duree_moyenne_pret,
      garantie_rachat: r.garantie_rachat,
      statistiques_publiques: r.statistiques_publiques,
      bonus_inscription: r.bonus_inscription,
      marche_secondaire: r.marche_secondaire,
      investissement_auto: r.investissement_auto,
      url_trustpilot: r.url_trustpilot,
      url_linkedin: r.url_linkedin,
      methode_remboursement: r.methode_remboursement,
      type_pret_defaut: r.type_pret_defaut,
      freq_interets_defaut: r.freq_interets_defaut,
      logo_filename: r.logo_filename,
      icone_filename: r.icone_filename,
      categories_inv: (r.categories_inv || []).map(c => c.nom),
      secteurs_inv: (r.secteurs_inv || []).map(s => s.nom),
      notation: notationByRef[r.id] || [],
    }));

    entries.push({ name: 'data.json', data: JSON.stringify(dataRows, null, 2) });

    // Types de garanties du user courant
    const garanties = db.prepare(
      'SELECT libelle, description, ordre FROM garantie_types WHERE user_id = ? ORDER BY ordre, id'
    ).all(req.user.id);
    entries.push({ name: 'garanties.json', data: JSON.stringify(garanties, null, 2) });

    // Include logo / icon files
    for (const r of rows) {
      for (const fname of [r.logo_filename, r.icone_filename]) {
        if (!fname) continue;
        const fpath = path.join(logosDir, fname);
        if (fs.existsSync(fpath)) {
          entries.push({ name: `logos/${fname}`, data: fs.readFileSync(fpath) });
        }
      }
    }

    const zipBuf = createZip(entries);
    const slug = 'referentiel-' + new Date().toISOString().slice(0, 10);
    res.setHeader('Content-Type', 'application/zip');
    res.setHeader('Content-Disposition', `attachment; filename="${slug}.zip"`);
    res.send(zipBuf);
  } catch (e) { next(e); }
});

// ── GET /api/referentiel/:id/export — export une seule entrée ───────────────
router.get('/:id/export', (req, res, next) => {
  try {
    const ref = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(req.params.id);
    if (!ref) throw new HttpError(404, 'Référentiel introuvable');
    const [enriched] = parsePaysOp(attachSecteursInv(attachCatsInv([ref])));

    const entries = [];
    const manifest = {
      version: '1.1',
      app: 'crowdlending',
      exported_at: new Date().toISOString(),
      count: 1,
      type: 'referentiel',
    };
    entries.push({ name: 'manifest.json', data: JSON.stringify(manifest, null, 2) });

    // Notation pour cette entrée
    const notRows = db.prepare(
      'SELECT * FROM referentiel_notation WHERE referentiel_id = ? ORDER BY ordre, id'
    ).all(ref.id);
    const notation = notRows.map(n => ({
      nom: n.nom,
      type: n.type,
      valeurs: n.valeurs ? JSON.parse(n.valeurs) : null,
      min_val: n.min_val,
      max_val: n.max_val,
      description: n.description,
      ordre: n.ordre,
    }));

    const dataRow = {
      nom: enriched.nom,
      url: enriched.url,
      domiciliation: enriched.domiciliation,
      fiscalite: enriched.fiscalite,
      taux_fiscalite_locale: enriched.taux_fiscalite_locale,
      type_produit_fiscal: enriched.type_produit_fiscal,
      description: enriched.description,
      annee_creation: enriched.annee_creation,
      investisseurs_types: enriched.investisseurs_types,
      regulateur: enriched.regulateur,
      numero_licence: enriched.numero_licence,
      is_regule: enriched.is_regule,
      pays_inscription: enriched.pays_inscription,
      pays_siege: enriched.pays_siege,
      pays_operation: enriched.pays_operation || [],
      investissement_minimum: enriched.investissement_minimum,
      rendement_annonce: enriched.rendement_annonce,
      nb_investisseurs: enriched.nb_investisseurs,
      volume_total_finance: enriched.volume_total_finance,
      duree_moyenne_pret: enriched.duree_moyenne_pret,
      garantie_rachat: enriched.garantie_rachat,
      statistiques_publiques: enriched.statistiques_publiques,
      bonus_inscription: enriched.bonus_inscription,
      marche_secondaire: enriched.marche_secondaire,
      investissement_auto: enriched.investissement_auto,
      url_trustpilot: enriched.url_trustpilot,
      url_linkedin: enriched.url_linkedin,
      methode_remboursement: enriched.methode_remboursement,
      type_pret_defaut: enriched.type_pret_defaut,
      freq_interets_defaut: enriched.freq_interets_defaut,
      logo_filename: enriched.logo_filename,
      icone_filename: enriched.icone_filename,
      categories_inv: (enriched.categories_inv || []).map(c => c.nom),
      secteurs_inv: (enriched.secteurs_inv || []).map(s => s.nom),
      notation,
    };

    entries.push({ name: 'data.json', data: JSON.stringify([dataRow], null, 2) });

    // Types de garanties du user courant
    const garanties = db.prepare(
      'SELECT libelle, description, ordre FROM garantie_types WHERE user_id = ? ORDER BY ordre, id'
    ).all(req.user.id);
    entries.push({ name: 'garanties.json', data: JSON.stringify(garanties, null, 2) });

    for (const fname of [enriched.logo_filename, enriched.icone_filename]) {
      if (!fname) continue;
      const fpath = path.join(logosDir, fname);
      if (fs.existsSync(fpath)) {
        entries.push({ name: `logos/${fname}`, data: fs.readFileSync(fpath) });
      }
    }

    const zipBuf = createZip(entries);
    const slug = enriched.nom.toLowerCase().replace(/[^a-z0-9]+/g, '-') + '-' + new Date().toISOString().slice(0, 10);
    res.setHeader('Content-Type', 'application/zip');
    res.setHeader('Content-Disposition', `attachment; filename="${slug}.zip"`);
    res.send(zipBuf);
  } catch (e) { next(e); }
});

// ── POST /api/referentiel/import-zip — import depuis un fichier ZIP ─────────
router.post('/import-zip', zipUpload.single('file'), async (req, res, next) => {
  try {
    if (!req.file) throw new HttpError(400, 'Fichier ZIP manquant');
    const zipEntries = readZip(req.file.buffer);

    const manifestEntry = zipEntries.find(e => e.name === 'manifest.json');
    const dataEntry     = zipEntries.find(e => e.name === 'data.json');
    if (!dataEntry) throw new HttpError(400, 'ZIP invalide : data.json manquant');

    const platforms = JSON.parse(dataEntry.data.toString('utf8'));
    if (!Array.isArray(platforms)) throw new HttpError(400, 'data.json doit être un tableau');

    // Normalise tag names to IDs (create global if missing)
    function resolveTagIds(names, table) {
      const ids = [];
      for (const nom of (names || [])) {
        const trimmed = nom.trim();
        if (!trimmed) continue;
        let row = db.prepare(`SELECT id FROM ${table} WHERE nom = ? AND user_id IS NULL`).get(trimmed);
        if (!row) {
          const r = db.prepare(`INSERT INTO ${table} (nom, user_id) VALUES (?, NULL)`).run(trimmed);
          row = { id: r.lastInsertRowid };
        }
        ids.push(row.id);
      }
      return ids;
    }

    // Build a map of images from the ZIP
    const imageMap = {};
    for (const e of zipEntries) {
      if (e.name.startsWith('logos/') && e.name.length > 6) {
        imageMap[path.basename(e.name)] = e.data;
      }
    }

    let created = 0;
    let updated = 0;
    const tx = db.transaction(() => {
      for (const p of platforms) {
        if (!p.nom) continue;

        const catsIds   = resolveTagIds(p.categories_inv, 'categories_inv');
        const sectsIds  = resolveTagIds(p.secteurs_inv, 'secteurs_inv');
        const paysOp    = Array.isArray(p.pays_operation) && p.pays_operation.length ? JSON.stringify(p.pays_operation) : null;

        const existing = db.prepare('SELECT id FROM plateformes_referentiel WHERE nom = ?').get(p.nom);

        const fields = [
          p.url || null, p.domiciliation || 'france', p.fiscalite || 'flat_tax',
          p.taux_fiscalite_locale ?? null, p.type_produit_fiscal || '2TT',
          p.methode_remboursement || 'portefeuille', p.type_pret_defaut ?? null, p.freq_interets_defaut ?? null,
          p.description ?? null, p.annee_creation ?? null,
          p.investisseurs_types ?? null,
          p.regulateur ?? null, p.numero_licence ?? null, p.is_regule ? 1 : 0,
          p.pays_inscription ?? null, p.pays_siege ?? null, paysOp,
          p.investissement_minimum ?? null, p.rendement_annonce ?? null,
          p.nb_investisseurs ?? null, p.volume_total_finance ?? null, p.duree_moyenne_pret ?? null,
          p.garantie_rachat ? 1 : 0, p.statistiques_publiques ? 1 : 0,
          p.bonus_inscription ? 1 : 0, p.marche_secondaire ? 1 : 0, p.investissement_auto ? 1 : 0,
          p.url_trustpilot || null, p.url_linkedin || null,
          p.logo_filename ?? null, p.icone_filename ?? null,
        ];

        let refId;
        if (existing) {
          db.prepare(`
            UPDATE plateformes_referentiel SET
              url=?, domiciliation=?, fiscalite=?, taux_fiscalite_locale=?, type_produit_fiscal=?,
              methode_remboursement=?, type_pret_defaut=?, freq_interets_defaut=?,
              description=?, annee_creation=?, investisseurs_types=?,
              regulateur=?, numero_licence=?, is_regule=?,
              pays_inscription=?, pays_siege=?, pays_operation=?,
              investissement_minimum=?, rendement_annonce=?,
              nb_investisseurs=?, volume_total_finance=?, duree_moyenne_pret=?,
              garantie_rachat=?, statistiques_publiques=?, bonus_inscription=?, marche_secondaire=?, investissement_auto=?,
              url_trustpilot=?, url_linkedin=?,
              logo_filename=?, icone_filename=?,
              updated_at=datetime('now')
            WHERE id=?
          `).run(...fields, existing.id);
          refId = existing.id;
          updated++;
        } else {
          const r = db.prepare(`
            INSERT INTO plateformes_referentiel
              (nom, url, domiciliation, fiscalite, taux_fiscalite_locale, type_produit_fiscal,
               methode_remboursement, type_pret_defaut, freq_interets_defaut,
               description, annee_creation, investisseurs_types,
               regulateur, numero_licence, is_regule,
               pays_inscription, pays_siege, pays_operation,
               investissement_minimum, rendement_annonce,
               nb_investisseurs, volume_total_finance, duree_moyenne_pret,
               garantie_rachat, statistiques_publiques, bonus_inscription, marche_secondaire, investissement_auto,
               url_trustpilot, url_linkedin,
               logo_filename, icone_filename, updated_at)
            VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,datetime('now'))
          `).run(p.nom, ...fields);
          refId = r.lastInsertRowid;
          created++;
        }

        // Sync categories_inv
        db.prepare('DELETE FROM referentiel_categories_inv WHERE referentiel_id = ?').run(refId);
        for (const id of catsIds) {
          db.prepare('INSERT OR IGNORE INTO referentiel_categories_inv (referentiel_id, categorie_id) VALUES (?,?)').run(refId, id);
        }
        // Sync secteurs_inv
        db.prepare('DELETE FROM referentiel_secteurs_inv WHERE referentiel_id = ?').run(refId);
        for (const id of sectsIds) {
          db.prepare('INSERT OR IGNORE INTO referentiel_secteurs_inv (referentiel_id, secteur_id) VALUES (?,?)').run(refId, id);
        }

        // Sync referentiel_notation
        if (Array.isArray(p.notation) && p.notation.length) {
          db.prepare('DELETE FROM referentiel_notation WHERE referentiel_id = ?').run(refId);
          for (const n of p.notation) {
            db.prepare(`
              INSERT INTO referentiel_notation (referentiel_id, nom, type, valeurs, min_val, max_val, description, ordre)
              VALUES (?,?,?,?,?,?,?,?)
            `).run(
              refId,
              (n.nom || '').trim(),
              n.type || 'etoiles',
              n.valeurs ? JSON.stringify(Array.isArray(n.valeurs) ? n.valeurs : [n.valeurs]) : null,
              n.min_val ?? null,
              n.max_val ?? null,
              n.description ?? null,
              n.ordre ?? 0,
            );
          }
        }

        // Write logo / icon images from ZIP
        for (const fname of [p.logo_filename, p.icone_filename]) {
          if (!fname || !imageMap[fname]) continue;
          const dest = path.join(logosDir, fname);
          fs.writeFileSync(dest, imageMap[fname]);
        }
      }
    });

    tx();

    // ── Import garanties ──────────────────────────────────────────────────────
    const garantiesEntry = zipEntries.find(e => e.name === 'garanties.json');
    if (garantiesEntry) {
      const garanties = JSON.parse(garantiesEntry.data.toString('utf8'));
      if (Array.isArray(garanties) && garanties.length) {
        const gtx = db.transaction(() => {
          for (const g of garanties) {
            const libelle = (g.libelle || '').trim();
            if (!libelle) continue;
            const existing = db.prepare(
              'SELECT id FROM garantie_types WHERE user_id = ? AND LOWER(libelle) = LOWER(?)'
            ).get(req.user.id, libelle);
            if (existing) {
              db.prepare(
                'UPDATE garantie_types SET description=?, ordre=? WHERE id=?'
              ).run(g.description ?? null, g.ordre ?? 0, existing.id);
            } else {
              db.prepare(
                'INSERT INTO garantie_types (user_id, libelle, description, ordre) VALUES (?,?,?,?)'
              ).run(req.user.id, libelle, g.description ?? null, g.ordre ?? 0);
            }
          }
        });
        gtx();
      }
    }

    res.json({ ok: true, created, updated, total: platforms.length });
  } catch (e) { next(e); }
});


// ── GET /api/referentiel/:id ───────────────────────────────────────────────
router.get('/:id', (req, res, next) => {
  try {
    const row = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(req.params.id);
    if (!row) throw new HttpError(404, 'Référentiel introuvable');
    const [enriched] = parsePaysOp(attachNotation(attachSecteursInv(attachCatsInv(attachCats([row])))));
    res.json(enriched);
  } catch (e) { next(e); }
});

// ── POST /api/referentiel ──────────────────────────────────────────────────
router.post('/', (req, res, next) => {
  try {
    const data = Schema.parse(req.body);
    const existing = db.prepare('SELECT id FROM plateformes_referentiel WHERE nom = ?').get(data.nom);
    if (existing) throw new HttpError(409, `Une entrée référentiel "${data.nom}" existe déjà`);

    const r = db.prepare(`
      INSERT INTO plateformes_referentiel
        (nom, url, domiciliation, fiscalite, taux_fiscalite_locale, type_produit_fiscal,
         methode_remboursement, type_pret_defaut, freq_interets_defaut,
         logo_filename, description,
         annee_creation, investisseurs_types,
         regulateur, numero_licence, is_regule,
         pays_inscription, pays_siege, pays_operation,
         investissement_minimum, rendement_annonce, nb_investisseurs, volume_total_finance, duree_moyenne_pret,
         garantie_rachat, statistiques_publiques, bonus_inscription, marche_secondaire, investissement_auto,
         url_trustpilot, url_linkedin, updated_at)
      VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?, datetime('now'))
    `).run(
      data.nom, data.url || null, data.domiciliation, data.fiscalite,
      data.taux_fiscalite_locale ?? null, data.type_produit_fiscal,
      data.methode_remboursement || 'portefeuille', data.type_pret_defaut ?? null, data.freq_interets_defaut ?? null,
      data.logo_filename ?? null, data.description ?? null,
      data.annee_creation ?? null, data.investisseurs_types ?? null,
      data.regulateur ?? null, data.numero_licence ?? null, data.is_regule ? 1 : 0,
      data.pays_inscription ?? null, data.pays_siege ?? null,
      data.pays_operation?.length ? JSON.stringify(data.pays_operation) : null,
      data.investissement_minimum ?? null, data.rendement_annonce ?? null,
      data.nb_investisseurs ?? null, data.volume_total_finance ?? null, data.duree_moyenne_pret ?? null,
      data.garantie_rachat ? 1 : 0, data.statistiques_publiques ? 1 : 0,
      data.bonus_inscription ? 1 : 0, data.marche_secondaire ? 1 : 0, data.investissement_auto ? 1 : 0,
      data.url_trustpilot || null, data.url_linkedin || null
    );

    const refId = r.lastInsertRowid;
    const tx = db.transaction(fn => fn());
    saveRelations(tx, refId, data.categories, data.notation, data.categories_inv_ids, data.secteurs_inv_ids);

    const row = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(refId);
    const [enriched] = parsePaysOp(attachNotation(attachSecteursInv(attachCatsInv(attachCats([row])))));
    enriched.nb_plateformes_liees = 0;
    res.status(201).json(enriched);
  } catch (e) { next(e); }
});

// ── PUT /api/referentiel/:id ───────────────────────────────────────────────
router.put('/:id', (req, res, next) => {
  try {
    const row = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(req.params.id);
    if (!row) throw new HttpError(404, 'Référentiel introuvable');

    const data = Schema.parse(req.body);

    // Vérifier unicité du nom si changé
    if (data.nom !== row.nom) {
      const dup = db.prepare('SELECT id FROM plateformes_referentiel WHERE nom = ? AND id != ?').get(data.nom, row.id);
      if (dup) throw new HttpError(409, `Une entrée référentiel "${data.nom}" existe déjà`);
    }

    db.prepare(`
      UPDATE plateformes_referentiel
      SET nom=?, url=?, domiciliation=?, fiscalite=?, taux_fiscalite_locale=?,
          type_produit_fiscal=?, methode_remboursement=?, type_pret_defaut=?, freq_interets_defaut=?,
          logo_filename=?, description=?,
          annee_creation=?, investisseurs_types=?,
          regulateur=?, numero_licence=?, is_regule=?,
          pays_inscription=?, pays_siege=?, pays_operation=?,
          investissement_minimum=?, rendement_annonce=?, nb_investisseurs=?,
          volume_total_finance=?, duree_moyenne_pret=?,
          garantie_rachat=?, statistiques_publiques=?, bonus_inscription=?,
          marche_secondaire=?, investissement_auto=?,
          url_trustpilot=?, url_linkedin=?, updated_at=datetime('now')
      WHERE id=?
    `).run(
      data.nom, data.url || null, data.domiciliation, data.fiscalite,
      data.taux_fiscalite_locale ?? null, data.type_produit_fiscal,
      data.methode_remboursement || 'portefeuille', data.type_pret_defaut ?? null, data.freq_interets_defaut ?? null,
      data.logo_filename ?? null, data.description ?? null,
      data.annee_creation ?? null, data.investisseurs_types ?? null,
      data.regulateur ?? null, data.numero_licence ?? null, data.is_regule ? 1 : 0,
      data.pays_inscription ?? null, data.pays_siege ?? null,
      data.pays_operation?.length ? JSON.stringify(data.pays_operation) : null,
      data.investissement_minimum ?? null, data.rendement_annonce ?? null,
      data.nb_investisseurs ?? null, data.volume_total_finance ?? null, data.duree_moyenne_pret ?? null,
      data.garantie_rachat ? 1 : 0, data.statistiques_publiques ? 1 : 0,
      data.bonus_inscription ? 1 : 0, data.marche_secondaire ? 1 : 0, data.investissement_auto ? 1 : 0,
      data.url_trustpilot || null, data.url_linkedin || null, row.id
    );

    const tx = db.transaction(fn => fn());
    saveRelations(tx, row.id, data.categories, data.notation, data.categories_inv_ids, data.secteurs_inv_ids);

    const updated = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(row.id);
    const nb = db.prepare('SELECT COUNT(*) AS n FROM plateformes WHERE referentiel_id = ?').get(row.id).n;
    const [enriched] = parsePaysOp(attachNotation(attachSecteursInv(attachCatsInv(attachCats([updated])))));
    enriched.nb_plateformes_liees = nb;
    res.json(enriched);
  } catch (e) { next(e); }
});

// ── DELETE /api/referentiel/:id ────────────────────────────────────────────
// Délie les plateformes liées (referentiel_id → null) avant suppression
router.delete('/:id', (req, res, next) => {
  try {
    const row = db.prepare('SELECT id FROM plateformes_referentiel WHERE id = ?').get(req.params.id);
    if (!row) throw new HttpError(404, 'Référentiel introuvable');

    db.transaction(() => {
      // Délier les plateformes (on ne supprime pas les données user)
      db.prepare('UPDATE plateformes SET referentiel_id = NULL WHERE referentiel_id = ?').run(row.id);
      db.prepare('DELETE FROM plateformes_referentiel WHERE id = ?').run(row.id);
    })();

    res.json({ deleted: true });
  } catch (e) { next(e); }
});

// ── GET /api/referentiel/:id/plateformes ───────────────────────────────────
// Liste les plateformes user liées à ce référentiel
router.get('/:id/plateformes', (req, res, next) => {
  try {
    const row = db.prepare('SELECT id FROM plateformes_referentiel WHERE id = ?').get(req.params.id);
    if (!row) throw new HttpError(404, 'Référentiel introuvable');

    const plateformes = db.prepare(`
      SELECT p.id, p.nom, p.domiciliation, p.fiscalite, p.overridden_fields,
             u.email AS user_email,
             inv.nom AS detenteur_nom, inv.prenom AS detenteur_prenom
      FROM plateformes p
      JOIN users u ON u.id = p.user_id
      LEFT JOIN investisseurs inv ON inv.id = p.investisseur_id
      WHERE p.referentiel_id = ?
      ORDER BY u.email, p.nom
    `).all(req.params.id);

    res.json(plateformes.map(p => ({
      ...p,
      overridden_fields: JSON.parse(p.overridden_fields || '[]'),
    })));
  } catch (e) { next(e); }
});

// ── POST /api/referentiel/:id/push ─────────────────────────────────────────
// Pousse les champs du référentiel vers les plateformes liées.
// Body { force: true } → écrase tous les champs (méthode dure), y compris les overrides utilisateur.
// Défaut (force absent ou false) → respecte overridden_fields (méthode douce).
router.post('/:id/push', (req, res, next) => {
  try {
    const ref = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(req.params.id);
    if (!ref) throw new HttpError(404, 'Référentiel introuvable');

    const force = req.body?.force === true;

    // Champs scalaires poussables
    const PUSHABLE = ['nom', 'url', 'domiciliation', 'fiscalite', 'taux_fiscalite_locale', 'type_produit_fiscal', 'logo_filename', 'methode_remboursement', 'type_pret_defaut', 'freq_interets_defaut'];

    // Catégories/secteurs du référentiel
    const refCatIds = db.prepare(
      'SELECT categorie_id FROM referentiel_categories_inv WHERE referentiel_id = ?'
    ).all(ref.id).map(r => r.categorie_id);
    const refSectIds = db.prepare(
      'SELECT secteur_id FROM referentiel_secteurs_inv WHERE referentiel_id = ?'
    ).all(ref.id).map(r => r.secteur_id);

    const plateformes = db.prepare(
      'SELECT id, overridden_fields FROM plateformes WHERE referentiel_id = ?'
    ).all(ref.id);

    let nb_updated = 0;

    db.transaction(() => {
      const insCat  = db.prepare('INSERT OR IGNORE INTO plateforme_categories_inv (plateforme_id, categorie_id) VALUES (?, ?)');
      const insSect = db.prepare('INSERT OR IGNORE INTO plateforme_secteurs_inv (plateforme_id, secteur_id) VALUES (?, ?)');
      const insInvCat  = db.prepare('INSERT OR IGNORE INTO investissement_categories_inv (investissement_id, categorie_id) VALUES (?, ?)');
      const insInvSect = db.prepare('INSERT OR IGNORE INTO investissement_secteurs_inv (investissement_id, secteur_id) VALUES (?, ?)');

      for (const plat of plateformes) {
        // ── Champs scalaires ──
        let fields;
        if (force) {
          fields = PUSHABLE;
        } else {
          const overridden = JSON.parse(plat.overridden_fields || '[]');
          fields = PUSHABLE.filter(f => !overridden.includes(f));
        }
        if (fields.length > 0) {
          const setParts = fields.map(f => `${f} = ?`).join(', ');
          const values   = fields.map(f => ref[f] ?? null);
          const extraSet = force ? ', overridden_fields = \'[]\'' : '';
          db.prepare(`UPDATE plateformes SET ${setParts}${extraSet} WHERE id = ?`).run(...values, plat.id);
        }

        // ── Catégories/secteurs ──
        if (force) {
          // Méthode dure : remplace toutes les associations
          db.prepare('DELETE FROM plateforme_categories_inv WHERE plateforme_id = ?').run(plat.id);
          db.prepare('DELETE FROM plateforme_secteurs_inv WHERE plateforme_id = ?').run(plat.id);
        }
        // Méthode douce : INSERT OR IGNORE (n'écrase pas les associations existantes)
        for (const catId of refCatIds) insCat.run(plat.id, catId);
        for (const sectId of refSectIds) insSect.run(plat.id, sectId);

        // Sync investissements actifs de la plateforme
        const invs = db.prepare(
          "SELECT id FROM investissements WHERE plateforme_id = ? AND statut NOT IN ('rembourse','cloture')"
        ).all(plat.id);
        for (const inv of invs) {
          if (force) {
            db.prepare('DELETE FROM investissement_categories_inv WHERE investissement_id = ?').run(inv.id);
            db.prepare('DELETE FROM investissement_secteurs_inv WHERE investissement_id = ?').run(inv.id);
          }
          for (const catId of refCatIds) insInvCat.run(inv.id, catId);
          for (const sectId of refSectIds) insInvSect.run(inv.id, sectId);
        }

        nb_updated++;
      }
    })();

    res.json({ pushed: true, force, nb_plateformes: plateformes.length, nb_updated });
  } catch (e) { next(e); }
});

// ── POST /api/referentiel/:id/logo ─────────────────────────────────────────
// Upload d'un logo pour une entrée du référentiel ; auto-push vers les plateformes liées
router.post('/:id/logo', upload.single('file'), async (req, res, next) => {
  try {
    const ref = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(req.params.id);
    if (!ref) throw new HttpError(404, 'Référentiel introuvable');
    if (!req.file) throw new HttpError(400, 'Fichier requis');

    // Traiter l'image (fond blanc transparent, conversion en PNG si besoin)
    const finalPath = await processLogoFile(req.file.path);
    const filename  = path.basename(finalPath);

    // Supprimer l'ancien logo s'il existe
    if (ref.logo_filename) {
      const old = path.join(logosDir, ref.logo_filename);
      if (fs.existsSync(old)) fs.unlink(old, () => {});
    }

    // Mettre à jour le référentiel
    db.prepare(`UPDATE plateformes_referentiel SET logo_filename=?, updated_at=datetime('now') WHERE id=?`)
      .run(filename, ref.id);

    // Auto-push logo_filename vers les plateformes liées (sauf si overridé)
    const plateformes = db.prepare('SELECT id, overridden_fields FROM plateformes WHERE referentiel_id = ?').all(ref.id);
    db.transaction(() => {
      for (const plat of plateformes) {
        const overridden = JSON.parse(plat.overridden_fields || '[]');
        if (!overridden.includes('logo_filename')) {
          db.prepare('UPDATE plateformes SET logo_filename=? WHERE id=?').run(filename, plat.id);
        }
      }
    })();

    res.json({
      logo_filename: filename,
      nb_plateformes_updated: plateformes.filter(p => !JSON.parse(p.overridden_fields || '[]').includes('logo_filename')).length
    });
  } catch (e) { next(e); }
});

// ── DELETE /api/referentiel/:id/logo ───────────────────────────────────────
router.delete('/:id/logo', async (req, res, next) => {
  try {
    const ref = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(req.params.id);
    if (!ref) throw new HttpError(404, 'Référentiel introuvable');

    if (ref.logo_filename) {
      const filePath = path.join(logosDir, ref.logo_filename);
      if (fs.existsSync(filePath)) fs.unlink(filePath, () => {});
    }

    db.prepare(`UPDATE plateformes_referentiel SET logo_filename=NULL, updated_at=datetime('now') WHERE id=?`).run(ref.id);

    // Pousser null vers les plateformes liées non-overridées
    const plateformes = db.prepare('SELECT id, overridden_fields FROM plateformes WHERE referentiel_id = ?').all(ref.id);
    db.transaction(() => {
      for (const plat of plateformes) {
        const overridden = JSON.parse(plat.overridden_fields || '[]');
        if (!overridden.includes('logo_filename')) {
          db.prepare('UPDATE plateformes SET logo_filename=NULL WHERE id=?').run(plat.id);
        }
      }
    })();

    res.json({ deleted: true });
  } catch (e) { next(e); }
});

// ── POST /api/referentiel/:id/icone ──────────────────────────────────────────
// Upload d'une icone pour une entree du referentiel ; auto-push vers les plateformes liees
router.post('/:id/icone', upload.single('file'), async (req, res, next) => {
  try {
    const ref = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(req.params.id);
    if (!ref) throw new HttpError(404, 'Referentiel introuvable');
    if (!req.file) throw new HttpError(400, 'Fichier requis');

    const finalPath = await processLogoFile(req.file.path);
    const filename  = path.basename(finalPath);

    if (ref.icone_filename) {
      const oldFile = path.join(logosDir, ref.icone_filename);
      if (fs.existsSync(oldFile)) fs.unlink(oldFile, () => {});
    }

    db.prepare(`UPDATE plateformes_referentiel SET icone_filename=?, updated_at=datetime('now') WHERE id=?`)
      .run(filename, ref.id);

    // Auto-push icone_filename vers les plateformes liées (sauf si overridé)
    const plateformesIcn = db.prepare('SELECT id, overridden_fields FROM plateformes WHERE referentiel_id = ?').all(ref.id);
    db.transaction(() => {
      for (const plat of plateformesIcn) {
        const overridden = JSON.parse(plat.overridden_fields || '[]');
        if (!overridden.includes('icone_filename')) {
          db.prepare('UPDATE plateformes SET icone_filename=? WHERE id=?').run(filename, plat.id);
        }
      }
    })();

    res.json({
      icone_filename: filename,
      nb_plateformes_updated: plateformesIcn.filter(p => !JSON.parse(p.overridden_fields || '[]').includes('icone_filename')).length
    });
  } catch (e) { next(e); }
});

// ── DELETE /api/referentiel/:id/icone ─────────────────────────────────────────
router.delete('/:id/icone', async (req, res, next) => {
  try {
    const ref = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(req.params.id);
    if (!ref) throw new HttpError(404, 'Referentiel introuvable');

    if (ref.icone_filename) {
      const filePath = path.join(logosDir, ref.icone_filename);
      if (fs.existsSync(filePath)) fs.unlink(filePath, () => {});
    }

    db.prepare(`UPDATE plateformes_referentiel SET icone_filename=NULL, updated_at=datetime('now') WHERE id=?`).run(ref.id);

    const plateformesIcn = db.prepare('SELECT id, overridden_fields FROM plateformes WHERE referentiel_id = ?').all(ref.id);
    db.transaction(() => {
      for (const plat of plateformesIcn) {
        const overridden = JSON.parse(plat.overridden_fields || '[]');
        if (!overridden.includes('icone_filename')) {
          db.prepare('UPDATE plateformes SET icone_filename=NULL WHERE id=?').run(plat.id);
        }
      }
    })();

    res.json({ deleted: true });
  } catch (e) { next(e); }
});


// -- NOTATION -- criteres par referentiel -----------------------------------------

const TYPES_VALIDES_NOT = ['etoiles', 'lettres', 'score', 'custom'];

function enrichNot(row) {
  return { ...row, valeurs: row.valeurs ? JSON.parse(row.valeurs) : null };
}

// GET /api/referentiel/:id/notation
router.get('/:id/notation', (req, res, next) => {
  try {
    const ref = db.prepare('SELECT id FROM plateformes_referentiel WHERE id = ?').get(req.params.id);
    if (!ref) throw new HttpError(404, 'Referentiel introuvable');
    const rows = db.prepare(
      'SELECT * FROM referentiel_notation WHERE referentiel_id = ? ORDER BY ordre, id'
    ).all(ref.id);
    res.json(rows.map(enrichNot));
  } catch (e) { next(e); }
});

// POST /api/referentiel/:id/notation
router.post('/:id/notation', (req, res, next) => {
  try {
    const ref = db.prepare('SELECT id FROM plateformes_referentiel WHERE id = ?').get(req.params.id);
    if (!ref) throw new HttpError(404, 'Referentiel introuvable');

    const { nom, type = 'etoiles', valeurs, min_val, max_val, description, ordre } = req.body || {};
    if (!nom?.trim()) throw new HttpError(400, 'nom est requis');
    if (!TYPES_VALIDES_NOT.includes(type)) throw new HttpError(400, 'type invalide');

    const r = db.prepare(`
      INSERT INTO referentiel_notation (referentiel_id, nom, type, valeurs, min_val, max_val, description, ordre)
      VALUES (?,?,?,?,?,?,?,?)
    `).run(
      ref.id, nom.trim(), type,
      (type === 'lettres' || type === 'custom')
        ? JSON.stringify(Array.isArray(valeurs) ? valeurs : String(valeurs || '').split(',').map(v => v.trim()).filter(Boolean))
        : null,
      type === 'score' ? Number(min_val ?? 0) : null,
      type === 'score' ? Number(max_val ?? 10) : null,
      description?.trim() || null,
      Number(ordre ?? 0),
    );
    res.status(201).json(enrichNot(db.prepare('SELECT * FROM referentiel_notation WHERE id = ?').get(r.lastInsertRowid)));
  } catch (e) { next(e); }
});

// PUT /api/referentiel/notation/:notationId
router.put('/notation/:notationId', (req, res, next) => {
  try {
    const existing = db.prepare('SELECT * FROM referentiel_notation WHERE id = ?').get(req.params.notationId);
    if (!existing) throw new HttpError(404, 'Critere introuvable');

    const { nom, type, valeurs, min_val, max_val, description, ordre } = req.body || {};
    const t = type || existing.type;
    if (!nom?.trim()) throw new HttpError(400, 'nom est requis');

    db.prepare(`
      UPDATE referentiel_notation SET nom=?, type=?, valeurs=?, min_val=?, max_val=?, description=?, ordre=?
      WHERE id=?
    `).run(
      nom.trim(), t,
      (t === 'lettres' || t === 'custom')
        ? JSON.stringify(Array.isArray(valeurs) ? valeurs : String(valeurs || '').split(',').map(v => v.trim()).filter(Boolean))
        : null,
      t === 'score' ? Number(min_val ?? 0) : null,
      t === 'score' ? Number(max_val ?? 10) : null,
      description?.trim() || null,
      Number(ordre ?? 0),
      req.params.notationId,
    );
    res.json(enrichNot(db.prepare('SELECT * FROM referentiel_notation WHERE id = ?').get(req.params.notationId)));
  } catch (e) { next(e); }
});

// DELETE /api/referentiel/notation/:notationId
router.delete('/notation/:notationId', (req, res, next) => {
  try {
    const existing = db.prepare('SELECT id FROM referentiel_notation WHERE id = ?').get(req.params.notationId);
    if (!existing) throw new HttpError(404, 'Critere introuvable');
    db.prepare('DELETE FROM referentiel_notation WHERE id = ?').run(req.params.notationId);
    res.json({ deleted: true });
  } catch (e) { next(e); }
});

export default router;
