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

const __dirname  = path.dirname(fileURLToPath(import.meta.url));
const logosDir   = path.resolve(__dirname, '../../../data/logos');
fs.mkdirSync(logosDir, { recursive: true });

/** Sanitise un nom de plateforme pour en faire un nom de fichier safe */
function sanitizeNom(nom) {
  return (nom || 'plateforme')
    .normalize('NFD').replace(/[̀-ͯ]/g, '')
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '_')
    .replace(/^_+|_+$/g, '') || 'plateforme';
}

const ALLOWED_MIMES = { 'image/svg+xml': 'svg', 'image/png': 'png', 'image/jpeg': 'jpg', 'image/jpg': 'jpg' };

const logoStorage = multer.diskStorage({
  destination: (_req, _file, cb) => cb(null, logosDir),
  filename: (req, file, cb) => {
    const plat = db.prepare('SELECT nom FROM plateformes WHERE id = ? AND user_id = ?')
      .get(req.params.id, req.user.id);
    const ext  = ALLOWED_MIMES[file.mimetype] || 'png';
    cb(null, `logo_${sanitizeNom(plat?.nom || String(req.params.id))}_${Date.now()}.${ext}`);
  },
});

const upload = multer({
  storage: logoStorage,
  limits: { fileSize: 2 * 1024 * 1024 },
  fileFilter: (_req, file, cb) => {
    if (ALLOWED_MIMES[file.mimetype]) cb(null, true);
    else cb(new HttpError(400, 'Format non supporté (SVG, PNG, JPEG uniquement)'));
  },
});

const router = Router();

const Schema = z.object({
  nom:                   z.string().min(1),
  url:                   z.string().url().optional().or(z.literal('')),
  notes:                 z.string().optional(),
  categories:            z.array(z.number().int().positive()).optional().default([]),
  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']).default('portefeuille'),
  investisseur_id:       z.number().int().positive().nullable().optional(),
  date_ouverture:        z.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional(),
  type_pret_defaut:      z.enum(['in_fine', 'amortissable', 'differe']).nullable().optional(),
  freq_interets_defaut:  z.enum(['mensuel', 'trimestriel', 'in_fine']).nullable().optional(),
  referentiel_id:        z.number().int().positive().nullable().optional(),
});

// Champs hérités du référentiel (comparés pour calculer overridden_fields)
const HERITABLE_FIELDS = ['nom', 'url', 'domiciliation', 'fiscalite', 'taux_fiscalite_locale', 'type_produit_fiscal', 'logo_filename', 'icone_filename', 'methode_remboursement', 'type_pret_defaut', 'freq_interets_defaut'];

/**
 * Calcule overridden_fields : champs dont la valeur diffère du référentiel.
 * Retourne le tableau mis à jour des champs overridés.
 */
function computeOverridden(ref, newValues, currentOverridden = []) {
  if (!ref) return currentOverridden;
  const overridden = new Set(currentOverridden);
  for (const field of HERITABLE_FIELDS) {
    const refVal  = ref[field]  ?? null;
    const newVal  = newValues[field] ?? null;
    // Comparer en string pour éviter les faux positifs number vs null
    if (String(refVal) !== String(newVal)) {
      overridden.add(field);
    } else {
      overridden.delete(field);
    }
  }
  return [...overridden];
}

function attachCategories(userId, rows) {
  if (rows.length === 0) return rows;
  const platIds = rows.map(r => r.id);
  const cats = db.prepare(`
    SELECT pc.plateforme_id, c.id, c.nom
    FROM plateforme_categories pc
    JOIN categories_plateforme c ON c.id = pc.categorie_id
    WHERE c.user_id = ?
      AND pc.plateforme_id IN (${platIds.map(() => '?').join(',')})
    ORDER BY c.nom
  `).all(userId, ...platIds);

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


function attachCategoriesInv(rows) {
  if (rows.length === 0) return rows;
  const ids = rows.map(r => r.id);

  // Tags propres à chaque plateforme
  const links = db.prepare(`
    SELECT pc.plateforme_id, c.id AS categorie_id, c.nom
    FROM plateforme_categories_inv pc
    JOIN categories_inv c ON c.id = pc.categorie_id
    WHERE pc.plateforme_id IN (${ids.map(() => '?').join(',')})
    ORDER BY c.nom
  `).all(...ids);
  const map = {};
  for (const l of links) {
    if (!map[l.plateforme_id]) map[l.plateforme_id] = [];
    map[l.plateforme_id].push({ id: l.categorie_id, nom: l.nom, is_inherited: false });
  }

  // Tags du référentiel pour les plateformes liées (héritage par fusion)
  const refIds = [...new Set(rows.filter(r => r.referentiel_id).map(r => r.referentiel_id))];
  const refCatMap = {};
  if (refIds.length > 0) {
    const refLinks = 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 (${refIds.map(() => '?').join(',')})
      ORDER BY c.nom
    `).all(...refIds);
    for (const l of refLinks) {
      if (!refCatMap[l.referentiel_id]) refCatMap[l.referentiel_id] = [];
      refCatMap[l.referentiel_id].push({ id: l.categorie_id, nom: l.nom });
    }
  }

  return rows.map(r => {
    const ownTags = map[r.id] || [];
    if (!r.referentiel_id) return { ...r, categories_inv: ownTags };
    const refTags = refCatMap[r.referentiel_id] || [];
    const refIdSet = new Set(refTags.map(t => t.id));
    const ownIds   = new Set(ownTags.map(t => t.id));
    for (const tag of ownTags) tag.is_inherited = refIdSet.has(tag.id);
    const merged = [...ownTags];
    for (const rt of refTags) {
      if (!ownIds.has(rt.id)) merged.push({ ...rt, is_inherited: true });
    }
    merged.sort((a, b) => a.nom.localeCompare(b.nom));
    return { ...r, categories_inv: merged };
  });
}

function attachSecteursInv(rows) {
  if (rows.length === 0) return rows;
  const ids = rows.map(r => r.id);

  const links = db.prepare(`
    SELECT ps.plateforme_id, s.id AS secteur_id, s.nom
    FROM plateforme_secteurs_inv ps
    JOIN secteurs_inv s ON s.id = ps.secteur_id
    WHERE ps.plateforme_id IN (${ids.map(() => '?').join(',')})
    ORDER BY s.nom
  `).all(...ids);
  const map = {};
  for (const l of links) {
    if (!map[l.plateforme_id]) map[l.plateforme_id] = [];
    map[l.plateforme_id].push({ id: l.secteur_id, nom: l.nom, is_inherited: false });
  }

  const refIds = [...new Set(rows.filter(r => r.referentiel_id).map(r => r.referentiel_id))];
  const refSectMap = {};
  if (refIds.length > 0) {
    const refLinks = 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 (${refIds.map(() => '?').join(',')})
      ORDER BY s.nom
    `).all(...refIds);
    for (const l of refLinks) {
      if (!refSectMap[l.referentiel_id]) refSectMap[l.referentiel_id] = [];
      refSectMap[l.referentiel_id].push({ id: l.secteur_id, nom: l.nom });
    }
  }

  return rows.map(r => {
    const ownTags = map[r.id] || [];
    if (!r.referentiel_id) return { ...r, secteurs_inv: ownTags };
    const refTags = refSectMap[r.referentiel_id] || [];
    const refIdSet = new Set(refTags.map(t => t.id));
    const ownIds   = new Set(ownTags.map(t => t.id));
    for (const tag of ownTags) tag.is_inherited = refIdSet.has(tag.id);
    const merged = [...ownTags];
    for (const rt of refTags) {
      if (!ownIds.has(rt.id)) merged.push({ ...rt, is_inherited: true });
    }
    merged.sort((a, b) => a.nom.localeCompare(b.nom));
    return { ...r, secteurs_inv: merged };
  });
}
function syncCategories(platId, catIds) {
  db.prepare('DELETE FROM plateforme_categories WHERE plateforme_id=?').run(platId);
  if (catIds.length === 0) return;
  const ins = db.prepare(
    'INSERT OR IGNORE INTO plateforme_categories (plateforme_id, categorie_id) VALUES (?,?)'
  );
  db.transaction((pid, ids) => {
    for (const cid of ids) ins.run(pid, cid);
  })(platId, catIds);
}

// ── Lecture référentiel (tous users authentifiés) ─────────────────────────
router.get('/referentiel-list', (_req, res) => {
  const rows = db.prepare(`
    SELECT pr.id, pr.nom, pr.domiciliation, pr.fiscalite,
           pr.taux_fiscalite_locale, pr.type_produit_fiscal, pr.logo_filename
    FROM plateformes_referentiel pr
    ORDER BY pr.nom
  `).all();
  res.json(rows);
});

router.get('/', (req, res) => {
  const rows = db.prepare(`
    SELECT p.id, p.nom, p.url, p.notes, p.domiciliation, p.fiscalite, p.taux_fiscalite_locale,
           p.type_produit_fiscal,
           p.methode_remboursement, p.investisseur_id, p.date_ouverture, p.logo_filename, p.icone_filename, p.created_at,
           p.type_pret_defaut, p.freq_interets_defaut,
           p.referentiel_id, p.overridden_fields,
           pr.nom AS referentiel_nom, pr.description AS referentiel_description,
           inv.nom AS investisseur_nom, inv.prenom AS investisseur_prenom,
           inv.type AS investisseur_type, inv.type_fiscal AS investisseur_type_fiscal,
           (SELECT COUNT(*) FROM investissements i
            JOIN investisseurs inv2 ON inv2.id = i.investisseur_id
            WHERE i.plateforme_id = p.id AND inv2.user_id = p.user_id) AS nb_investissements
    FROM plateformes p
    LEFT JOIN investisseurs inv ON inv.id = p.investisseur_id
    LEFT JOIN plateformes_referentiel pr ON pr.id = p.referentiel_id
    WHERE p.user_id = ?
    ORDER BY p.nom
  `).all(req.user.id);
  const enriched = rows.map(r => ({
    ...r,
    overridden_fields: JSON.parse(r.overridden_fields || '[]'),
  }));
  const withCats = attachCategories(req.user.id, enriched);
  const withCatsInv = attachCategoriesInv(withCats);
  const withAll = attachSecteursInv(withCatsInv);
  res.json(withAll);
});

router.post('/', (req, res, next) => {
  try {
    const body = Schema.parse(req.body);
    let fiscalite = body.domiciliation === 'FR' ? 'flat_tax' : body.fiscalite;
    let taux = fiscalite === 'avec_fiscalite_locale' ? (body.taux_fiscalite_locale ?? null) : null;
    let typeProduitFiscal = body.domiciliation === 'FR' ? (body.type_produit_fiscal ?? '2TT') : '2TT';
    let referentielId = body.referentiel_id ?? null;

    // Si un référentiel est sélectionné, hériter ses valeurs (pas encore d'overrides)
    if (referentielId) {
      const ref = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(referentielId);
      if (!ref) throw new HttpError(404, 'Référentiel introuvable');
      // Les champs du body priment (l'user peut déjà avoir modifié à la création)
      // On calcule les overrides par rapport au référentiel
    }

    const r = db.prepare(`
      INSERT INTO plateformes
        (user_id, nom, url, notes, domiciliation, fiscalite, taux_fiscalite_locale, type_produit_fiscal,
         methode_remboursement, investisseur_id, date_ouverture,
         type_pret_defaut, freq_interets_defaut,
         referentiel_id, overridden_fields)
      VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
    `).run(
      req.user.id, body.nom, body.url || null, body.notes || null,
      body.domiciliation, fiscalite, taux, typeProduitFiscal,
      body.methode_remboursement, body.investisseur_id ?? null, body.date_ouverture || null,
      body.type_pret_defaut ?? null, body.freq_interets_defaut ?? null,
      referentielId,
      '[]' // toujours vide à la création — les overrides se calculent au premier PUT
    );
    const id = r.lastInsertRowid;
    syncCategories(id, body.categories);
    res.status(201).json({
      id, ...body,
      fiscalite, taux_fiscalite_locale: taux, type_produit_fiscal: typeProduitFiscal,
      referentiel_id: referentielId, overridden_fields: [],
    });
  } catch (e) { next(e); }
});

// ── Multer memStorage 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/plateformes/export — exporte toutes les plateformes de l'user ─
router.get('/export', (req, res, next) => {
  try {
    let rows = db.prepare(`
      SELECT p.*, inv.nom AS investisseur_nom, inv.prenom AS investisseur_prenom
      FROM plateformes p
      LEFT JOIN investisseurs inv ON inv.id = p.investisseur_id
      WHERE p.user_id = ?
      ORDER BY p.nom
    `).all(req.user.id);
    rows = attachCategoriesInv(rows);
    rows = attachSecteursInv(rows);

    // Attach legacy categories
    const platIds = rows.map(r => r.id);
    let catsLegacy = [];
    if (platIds.length > 0) {
      catsLegacy = db.prepare(`
        SELECT pc.plateforme_id, c.nom
        FROM plateforme_categories pc JOIN categories_plateforme c ON c.id = pc.categorie_id
        WHERE c.user_id = ? AND pc.plateforme_id IN (${platIds.map(() => '?').join(',')})
      `).all(req.user.id, ...platIds);
    }
    const legacyMap = {};
    for (const c of catsLegacy) {
      if (!legacyMap[c.plateforme_id]) legacyMap[c.plateforme_id] = [];
      legacyMap[c.plateforme_id].push(c.nom);
    }

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

    const dataRows = rows.map(r => ({
      nom: r.nom,
      url: r.url,
      notes: r.notes,
      domiciliation: r.domiciliation,
      fiscalite: r.fiscalite,
      taux_fiscalite_locale: r.taux_fiscalite_locale,
      type_produit_fiscal: r.type_produit_fiscal,
      methode_remboursement: r.methode_remboursement,
      date_ouverture: r.date_ouverture,
      type_pret_defaut: r.type_pret_defaut,
      freq_interets_defaut: r.freq_interets_defaut,
      logo_filename: r.logo_filename,
      icone_filename: r.icone_filename,
      investisseur_nom: r.investisseur_nom,
      investisseur_prenom: r.investisseur_prenom,
      categories: legacyMap[r.id] || [],
      categories_inv: (r.categories_inv || []).map(c => c.nom),
      secteurs_inv: (r.secteurs_inv || []).map(s => s.nom),
    }));

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

    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 = 'plateformes-' + 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/plateformes/:id/export — exporte une plateforme ──────────────
router.get('/:id/export', (req, res, next) => {
  try {
    const p = db.prepare(`
      SELECT p.*, inv.nom AS investisseur_nom, inv.prenom AS investisseur_prenom
      FROM plateformes p LEFT JOIN investisseurs inv ON inv.id = p.investisseur_id
      WHERE p.id = ? AND p.user_id = ?
    `).get(req.params.id, req.user.id);
    if (!p) throw new HttpError(404, 'Plateforme introuvable');

    const [withCatsInv] = attachCategoriesInv([p]);
    const [withAll] = attachSecteursInv([withCatsInv]);

    const catsLegacy = db.prepare(`
      SELECT c.nom FROM plateforme_categories pc
      JOIN categories_plateforme c ON c.id = pc.categorie_id
      WHERE pc.plateforme_id = ? AND c.user_id = ?
    `).all(p.id, req.user.id).map(c => c.nom);

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

    const dataRow = {
      nom: withAll.nom, url: withAll.url, notes: withAll.notes,
      domiciliation: withAll.domiciliation, fiscalite: withAll.fiscalite,
      taux_fiscalite_locale: withAll.taux_fiscalite_locale,
      type_produit_fiscal: withAll.type_produit_fiscal,
      methode_remboursement: withAll.methode_remboursement,
      date_ouverture: withAll.date_ouverture,
      type_pret_defaut: withAll.type_pret_defaut, freq_interets_defaut: withAll.freq_interets_defaut,
      logo_filename: withAll.logo_filename, icone_filename: withAll.icone_filename,
      investisseur_nom: withAll.investisseur_nom, investisseur_prenom: withAll.investisseur_prenom,
      categories: catsLegacy,
      categories_inv: (withAll.categories_inv || []).map(c => c.nom),
      secteurs_inv: (withAll.secteurs_inv || []).map(s => s.nom),
    };
    entries.push({ name: 'data.json', data: JSON.stringify([dataRow], null, 2) });

    for (const fname of [withAll.logo_filename, withAll.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 = withAll.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/plateformes/import-zip — importe un ZIP de plateformes ──────
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 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');

    // Résoudre investisseur par nom+prénom
    const userInvestisseurs = db.prepare('SELECT * FROM investisseurs WHERE user_id = ?').all(req.user.id);
    function resolveInvestisseur(nom, prenom) {
      if (!nom) return userInvestisseurs[0]?.id ?? null;
      const match = userInvestisseurs.find(i =>
        i.nom?.toLowerCase() === nom?.toLowerCase() && i.prenom?.toLowerCase() === prenom?.toLowerCase()
      ) || userInvestisseurs.find(i => i.nom?.toLowerCase() === nom?.toLowerCase());
      return match?.id ?? userInvestisseurs[0]?.id ?? null;
    }

    // Résoudre categories_inv et secteurs_inv par nom (globaux puis user)
    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 OR user_id = ?)`).get(trimmed, req.user.id);
        if (!row) {
          const r = db.prepare(`INSERT INTO ${table} (nom, user_id) VALUES (?, ?)`).run(trimmed, req.user.id);
          row = { id: r.lastInsertRowid };
        }
        ids.push(row.id);
      }
      return ids;
    }

    // Résoudre catégories legacy
    function resolveLegacyCatIds(noms) {
      const ids = [];
      for (const nom of (noms || [])) {
        const trimmed = nom.trim();
        if (!trimmed) continue;
        let row = db.prepare('SELECT id FROM categories_plateforme WHERE nom = ? AND user_id = ?').get(trimmed, req.user.id);
        if (!row) {
          const r = db.prepare('INSERT INTO categories_plateforme (nom, user_id) VALUES (?, ?)').run(trimmed, req.user.id);
          row = { id: r.lastInsertRowid };
        }
        ids.push(row.id);
      }
      return ids;
    }

    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 fiscalite = p.domiciliation === 'FR' ? 'flat_tax' : (p.fiscalite || 'flat_tax');
        const taux = fiscalite === 'avec_fiscalite_locale' ? (p.taux_fiscalite_locale ?? null) : null;
        const investisseurId = resolveInvestisseur(p.investisseur_nom, p.investisseur_prenom);
        const catsInvIds  = resolveTagIds(p.categories_inv, 'categories_inv');
        const sectsInvIds = resolveTagIds(p.secteurs_inv, 'secteurs_inv');
        const legacyCatIds = resolveLegacyCatIds(p.categories);

        const existing = db.prepare('SELECT id FROM plateformes WHERE nom = ? AND user_id = ?').get(p.nom, req.user.id);
        let platId;

        const fields = [
          p.url || null, p.notes || null,
          p.domiciliation || 'france', fiscalite, taux,
          p.type_produit_fiscal || '2TT', p.methode_remboursement || 'portefeuille',
          investisseurId, p.date_ouverture || null,
          p.type_pret_defaut || null, p.freq_interets_defaut || null,
          p.logo_filename || null, p.icone_filename || null,
        ];

        if (existing) {
          db.prepare(`
            UPDATE plateformes SET url=?, notes=?, domiciliation=?, fiscalite=?, taux_fiscalite_locale=?,
              type_produit_fiscal=?, methode_remboursement=?, investisseur_id=?, date_ouverture=?,
              type_pret_defaut=?, freq_interets_defaut=?,
              logo_filename=?, icone_filename=?
            WHERE id=? AND user_id=?
          `).run(...fields, existing.id, req.user.id);
          platId = existing.id;
          updated++;
        } else {
          const r = db.prepare(`
            INSERT INTO plateformes
              (user_id, nom, url, notes, domiciliation, fiscalite, taux_fiscalite_locale,
               type_produit_fiscal, methode_remboursement, investisseur_id, date_ouverture,
               type_pret_defaut, freq_interets_defaut,
               logo_filename, icone_filename, overridden_fields)
            VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
          `).run(req.user.id, p.nom, ...fields, '[]');
          platId = r.lastInsertRowid;
          created++;
        }

        // Sync catégories legacy
        syncCategories(platId, legacyCatIds);
        // Sync categories_inv
        db.prepare('DELETE FROM plateforme_categories_inv WHERE plateforme_id = ?').run(platId);
        for (const id of catsInvIds) db.prepare('INSERT OR IGNORE INTO plateforme_categories_inv (plateforme_id, categorie_id) VALUES (?,?)').run(platId, id);
        // Sync secteurs_inv
        db.prepare('DELETE FROM plateforme_secteurs_inv WHERE plateforme_id = ?').run(platId);
        for (const id of sectsInvIds) db.prepare('INSERT OR IGNORE INTO plateforme_secteurs_inv (plateforme_id, secteur_id) VALUES (?,?)').run(platId, id);

        // Images
        for (const fname of [p.logo_filename, p.icone_filename]) {
          if (!fname || !imageMap[fname]) continue;
          fs.writeFileSync(path.join(logosDir, fname), imageMap[fname]);
        }
      }
    });
    tx();
    res.json({ ok: true, created, updated, total: platforms.length });
  } catch (e) { next(e); }
});


router.put('/:id', (req, res, next) => {
  try {
    const body = Schema.parse(req.body);
    const fiscalite = body.domiciliation === 'FR' ? 'flat_tax' : body.fiscalite;
    const taux = fiscalite === 'avec_fiscalite_locale' ? (body.taux_fiscalite_locale ?? null) : null;
    const typeProduitFiscal = body.domiciliation === 'FR' ? (body.type_produit_fiscal ?? '2TT') : '2TT';

    // Récupérer l'état actuel pour calculer les overrides
    const current = db.prepare('SELECT referentiel_id, overridden_fields, logo_filename FROM plateformes WHERE id = ? AND user_id = ?')
      .get(req.params.id, req.user.id);
    if (!current) throw new HttpError(404, 'Not found');

    // Calculer overridden_fields si la plateforme est liée à un référentiel
    let overriddenFields = JSON.parse(current.overridden_fields || '[]');
    if (current.referentiel_id) {
      const ref = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(current.referentiel_id);
      const newValues = {
        nom: body.nom,
        url: body.url || null,
        domiciliation: body.domiciliation,
        fiscalite,
        taux_fiscalite_locale: taux,
        type_produit_fiscal: typeProduitFiscal,
        logo_filename: current.logo_filename, // logo géré séparément
        methode_remboursement: body.methode_remboursement,
        type_pret_defaut: body.type_pret_defaut ?? null,
        freq_interets_defaut: body.freq_interets_defaut ?? null,
      };
      overriddenFields = computeOverridden(ref, newValues, overriddenFields);
    }

    const r = db.prepare(`
      UPDATE plateformes
      SET nom=?, url=?, notes=?, domiciliation=?, fiscalite=?, taux_fiscalite_locale=?,
          type_produit_fiscal=?, methode_remboursement=?, investisseur_id=?, date_ouverture=?,
          type_pret_defaut=?, freq_interets_defaut=?,
          overridden_fields=?
      WHERE id=? AND user_id=?
    `).run(
      body.nom, body.url || null, body.notes || null, body.domiciliation, fiscalite, taux,
      typeProduitFiscal, body.methode_remboursement, body.investisseur_id ?? null, body.date_ouverture || null,
      body.type_pret_defaut ?? null, body.freq_interets_defaut ?? null,
      JSON.stringify(overriddenFields),
      req.params.id, req.user.id
    );
    if (r.changes === 0) throw new HttpError(404, 'Not found');
    syncCategories(Number(req.params.id), body.categories);
    res.json({
      id: Number(req.params.id), ...body,
      fiscalite, taux_fiscalite_locale: taux, type_produit_fiscal: typeProduitFiscal,
      referentiel_id: current.referentiel_id,
      overridden_fields: overriddenFields,
    });
  } catch (e) { next(e); }
});

router.delete('/:id', (req, res, next) => {
  try {
    // Récupère le logo avant suppression pour effacer le fichier
    const plat = db.prepare('SELECT logo_filename FROM plateformes WHERE id=? AND user_id=?')
      .get(req.params.id, req.user.id);
    if (!plat) throw new HttpError(404, 'Not found');
    const r = db.prepare('DELETE FROM plateformes WHERE id=? AND user_id=?')
      .run(req.params.id, req.user.id);
    if (r.changes === 0) throw new HttpError(404, 'Not found');
    if (plat.logo_filename) {
      const filePath = path.join(logosDir, plat.logo_filename);
      fs.unlink(filePath, () => {}); // silencieux si déjà supprimé
    }
    res.status(204).end();
  } catch (e) { next(e); }
});

// ── Reset aux valeurs du référentiel ──────────────────────────────────────
router.post('/:id/reset', (req, res, next) => {
  try {
    const plat = db.prepare('SELECT * FROM plateformes WHERE id = ? AND user_id = ?')
      .get(req.params.id, req.user.id);
    if (!plat) throw new HttpError(404, 'Not found');
    if (!plat.referentiel_id) throw new HttpError(400, 'Cette plateforme n\'est liée à aucun référentiel');

    const ref = db.prepare('SELECT * FROM plateformes_referentiel WHERE id = ?').get(plat.referentiel_id);
    if (!ref) throw new HttpError(404, 'Référentiel introuvable');

    db.prepare(`
      UPDATE plateformes
      SET nom=?, domiciliation=?, fiscalite=?, taux_fiscalite_locale=?,
          type_produit_fiscal=?, logo_filename=?, overridden_fields='[]'
      WHERE id=? AND user_id=?
    `).run(
      ref.nom, ref.domiciliation, ref.fiscalite, ref.taux_fiscalite_locale ?? null,
      ref.type_produit_fiscal, ref.logo_filename ?? null,
      req.params.id, req.user.id
    );

    const updated = db.prepare('SELECT * FROM plateformes WHERE id = ?').get(req.params.id);
    res.json({ ...updated, overridden_fields: [] });
  } catch (e) { next(e); }
});

// ── Upload logo ───────────────────────────────────────────────────────────
router.post('/:id/logo', upload.single('logo'), (req, res, next) => {
  try {
    if (!req.file) throw new HttpError(400, 'Aucun fichier reçu');

    // Supprime l'ancien logo s'il diffère du nouveau
    const old = db.prepare('SELECT logo_filename FROM plateformes WHERE id=? AND user_id=?')
      .get(req.params.id, req.user.id);
    if (old?.logo_filename && old.logo_filename !== req.file.filename) {
      fs.unlink(path.join(logosDir, old.logo_filename), () => {});
    }

    db.prepare('UPDATE plateformes SET logo_filename=? WHERE id=? AND user_id=?')
      .run(req.file.filename, req.params.id, req.user.id);

    res.json({ logo_filename: req.file.filename });
  } catch (e) { next(e); }
});

// ── Suppression logo ──────────────────────────────────────────────────────
router.delete('/:id/logo', (req, res, next) => {
  try {
    const plat = db.prepare('SELECT logo_filename FROM plateformes WHERE id=? AND user_id=?')
      .get(req.params.id, req.user.id);
    if (!plat) throw new HttpError(404, 'Not found');
    if (plat.logo_filename) {
      fs.unlink(path.join(logosDir, plat.logo_filename), () => {});
      db.prepare("UPDATE plateformes SET logo_filename=NULL WHERE id=? AND user_id=?")
        .run(req.params.id, req.user.id);
    }
    res.status(204).end();
  } catch (e) { next(e); }
});

export default router;
