/**
 * Routes associations catégories/secteurs pour plateformes et investissements.
 *
 * GET    /api/plateformes/:id/categories-inv
 * PUT    /api/plateformes/:id/categories-inv      { ids: [1,2,3] }
 * GET    /api/plateformes/:id/secteurs-inv
 * PUT    /api/plateformes/:id/secteurs-inv         { ids: [1,2,3] }
 *
 * GET    /api/investissements/:id/categories-inv
 * PUT    /api/investissements/:id/categories-inv   { ids: [1,2,3] }
 * GET    /api/investissements/:id/secteurs-inv
 * PUT    /api/investissements/:id/secteurs-inv     { ids: [1,2,3] }
 *
 * Toutes ces routes sont montées sous requireAuth.
 * La vérification de propriété (via investisseur.user_id) est faite sur chaque route.
 */

import { Router } from 'express';
import { z } from 'zod';
import db from '../db/index.js';
import { HttpError } from '../middleware/errorHandler.js';

const router = Router();

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

/** Vérifie que la plateforme appartient à l'utilisateur connecté. */
function checkPlatOwner(platId, userId) {
  const row = db.prepare(`
    SELECT p.id FROM plateformes p
    JOIN investisseurs i ON i.id = p.investisseur_id
    WHERE p.id = ? AND i.user_id = ?
  `).get(platId, userId);
  if (!row) throw new HttpError(404, 'Plateforme introuvable ou accès refusé.');
  return row;
}

/** Vérifie que l'investissement appartient à l'utilisateur connecté. */
function checkInvOwner(invId, userId) {
  const row = db.prepare(`
    SELECT inv.id, inv.plateforme_id FROM investissements inv
    JOIN investisseurs i ON i.id = inv.investisseur_id
    WHERE inv.id = ? AND i.user_id = ?
  `).get(invId, userId);
  if (!row) throw new HttpError(404, 'Investissement introuvable ou accès refusé.');
  return row;
}

/** Vérifie que les ids fournis sont accessibles à l'utilisateur (globaux ou privés). */
function checkCatIds(ids, userId) {
  for (const id of ids) {
    const row = db.prepare(
      'SELECT id FROM categories_inv WHERE id = ? AND (user_id IS NULL OR user_id = ?)'
    ).get(id, userId);
    if (!row) throw new HttpError(400, `Catégorie ${id} introuvable ou non autorisée.`);
  }
}

function checkSectIds(ids, userId) {
  for (const id of ids) {
    const row = db.prepare(
      'SELECT id FROM secteurs_inv WHERE id = ? AND (user_id IS NULL OR user_id = ?)'
    ).get(id, userId);
    if (!row) throw new HttpError(400, `Secteur ${id} introuvable ou non autorisé.`);
  }
}

const IdsSchema = z.object({ ids: z.array(z.number().int()).default([]) });

// ── Plateforme → catégories ────────────────────────────────────────────────

router.get('/plateformes/:id/categories-inv', (req, res, next) => {
  try {
    checkPlatOwner(req.params.id, req.user.id);
    const rows = db.prepare(`
      SELECT c.id, c.nom, CASE WHEN c.user_id IS NULL THEN 1 ELSE 0 END AS is_global, 0 AS is_inherited
      FROM plateforme_categories_inv pc
      JOIN categories_inv c ON c.id = pc.categorie_id
      WHERE pc.plateforme_id = ?
      ORDER BY is_global DESC, c.nom
    `).all(req.params.id);

    // Merge tags du référentiel avec is_inherited: 1
    const plat = db.prepare('SELECT referentiel_id FROM plateformes WHERE id = ?').get(req.params.id);
    if (plat?.referentiel_id) {
      const refCats = db.prepare(`
        SELECT c.id, c.nom, CASE WHEN c.user_id IS NULL THEN 1 ELSE 0 END AS is_global
        FROM referentiel_categories_inv rc
        JOIN categories_inv c ON c.id = rc.categorie_id
        WHERE rc.referentiel_id = ?
      `).all(plat.referentiel_id);
      const refIdSet = new Set(refCats.map(r => r.id));
      for (const row of rows) if (refIdSet.has(row.id)) row.is_inherited = 1;
      const ownIds = new Set(rows.map(r => r.id));
      for (const rc of refCats) {
        if (!ownIds.has(rc.id)) rows.push({ ...rc, is_inherited: 1 });
      }
      rows.sort((a, b) => a.nom.localeCompare(b.nom));
    }
    res.json(rows);
  } catch (e) { next(e); }
});

router.put('/plateformes/:id/categories-inv', (req, res, next) => {
  try {
    const { ids } = IdsSchema.parse(req.body);
    const userId = req.user.id;
    checkPlatOwner(req.params.id, userId);
    checkCatIds(ids, userId);

    // Toujours inclure les tags hérités du référentiel
    const plat = db.prepare('SELECT referentiel_id FROM plateformes WHERE id = ?').get(req.params.id);
    let allIds = [...ids];
    if (plat?.referentiel_id) {
      const refCatIds = db.prepare('SELECT categorie_id FROM referentiel_categories_inv WHERE referentiel_id = ?')
        .all(plat.referentiel_id).map(r => r.categorie_id);
      allIds = [...new Set([...refCatIds, ...ids])];
    }

    db.transaction(() => {
      db.prepare('DELETE FROM plateforme_categories_inv WHERE plateforme_id = ?').run(req.params.id);
      const ins = db.prepare('INSERT INTO plateforme_categories_inv (plateforme_id, categorie_id) VALUES (?, ?)');
      for (const id of allIds) ins.run(req.params.id, id);
      syncInvestissementsCategories(req.params.id, allIds);
    })();
    res.json({ ok: true });
  } catch (e) { next(e); }
});

// ── Plateforme → secteurs ──────────────────────────────────────────────────

router.get('/plateformes/:id/secteurs-inv', (req, res, next) => {
  try {
    checkPlatOwner(req.params.id, req.user.id);
    const rows = db.prepare(`
      SELECT s.id, s.nom, CASE WHEN s.user_id IS NULL THEN 1 ELSE 0 END AS is_global, 0 AS is_inherited
      FROM plateforme_secteurs_inv ps
      JOIN secteurs_inv s ON s.id = ps.secteur_id
      WHERE ps.plateforme_id = ?
      ORDER BY is_global DESC, s.nom
    `).all(req.params.id);

    const plat = db.prepare('SELECT referentiel_id FROM plateformes WHERE id = ?').get(req.params.id);
    if (plat?.referentiel_id) {
      const refSects = db.prepare(`
        SELECT s.id, s.nom, CASE WHEN s.user_id IS NULL THEN 1 ELSE 0 END AS is_global
        FROM referentiel_secteurs_inv rs
        JOIN secteurs_inv s ON s.id = rs.secteur_id
        WHERE rs.referentiel_id = ?
      `).all(plat.referentiel_id);
      const refIdSet = new Set(refSects.map(r => r.id));
      for (const row of rows) if (refIdSet.has(row.id)) row.is_inherited = 1;
      const ownIds = new Set(rows.map(r => r.id));
      for (const rs of refSects) {
        if (!ownIds.has(rs.id)) rows.push({ ...rs, is_inherited: 1 });
      }
      rows.sort((a, b) => a.nom.localeCompare(b.nom));
    }
    res.json(rows);
  } catch (e) { next(e); }
});

router.put('/plateformes/:id/secteurs-inv', (req, res, next) => {
  try {
    const { ids } = IdsSchema.parse(req.body);
    const userId = req.user.id;
    checkPlatOwner(req.params.id, userId);
    checkSectIds(ids, userId);

    const plat = db.prepare('SELECT referentiel_id FROM plateformes WHERE id = ?').get(req.params.id);
    let allIds = [...ids];
    if (plat?.referentiel_id) {
      const refSectIds = db.prepare('SELECT secteur_id FROM referentiel_secteurs_inv WHERE referentiel_id = ?')
        .all(plat.referentiel_id).map(r => r.secteur_id);
      allIds = [...new Set([...refSectIds, ...ids])];
    }

    db.transaction(() => {
      db.prepare('DELETE FROM plateforme_secteurs_inv WHERE plateforme_id = ?').run(req.params.id);
      const ins = db.prepare('INSERT INTO plateforme_secteurs_inv (plateforme_id, secteur_id) VALUES (?, ?)');
      for (const id of allIds) ins.run(req.params.id, id);
      syncInvestissementsSecteurs(req.params.id, allIds);
    })();
    res.json({ ok: true });
  } catch (e) { next(e); }
});

// ── Investissement → catégories ────────────────────────────────────────────

router.get('/investissements/:id/categories-inv', (req, res, next) => {
  try {
    checkInvOwner(req.params.id, req.user.id);
    const rows = db.prepare(`
      SELECT c.id, c.nom, CASE WHEN c.user_id IS NULL THEN 1 ELSE 0 END AS is_global
      FROM investissement_categories_inv ic
      JOIN categories_inv c ON c.id = ic.categorie_id
      WHERE ic.investissement_id = ?
      ORDER BY is_global DESC, c.nom
    `).all(req.params.id);
    res.json(rows);
  } catch (e) { next(e); }
});

router.put('/investissements/:id/categories-inv', (req, res, next) => {
  try {
    const { ids } = IdsSchema.parse(req.body);
    const userId = req.user.id;
    checkInvOwner(req.params.id, userId);
    checkCatIds(ids, userId);
    db.transaction(() => {
      db.prepare('DELETE FROM investissement_categories_inv WHERE investissement_id = ?').run(req.params.id);
      const ins = db.prepare('INSERT INTO investissement_categories_inv (investissement_id, categorie_id) VALUES (?, ?)');
      for (const id of ids) ins.run(req.params.id, id);
    })();
    res.json({ ok: true });
  } catch (e) { next(e); }
});

// ── Investissement → secteurs ──────────────────────────────────────────────

router.get('/investissements/:id/secteurs-inv', (req, res, next) => {
  try {
    checkInvOwner(req.params.id, req.user.id);
    const rows = db.prepare(`
      SELECT s.id, s.nom, CASE WHEN s.user_id IS NULL THEN 1 ELSE 0 END AS is_global
      FROM investissement_secteurs_inv is2
      JOIN secteurs_inv s ON s.id = is2.secteur_id
      WHERE is2.investissement_id = ?
      ORDER BY is_global DESC, s.nom
    `).all(req.params.id);
    res.json(rows);
  } catch (e) { next(e); }
});

router.put('/investissements/:id/secteurs-inv', (req, res, next) => {
  try {
    const { ids } = IdsSchema.parse(req.body);
    const userId = req.user.id;
    checkInvOwner(req.params.id, userId);
    checkSectIds(ids, userId);
    db.transaction(() => {
      db.prepare('DELETE FROM investissement_secteurs_inv WHERE investissement_id = ?').run(req.params.id);
      const ins = db.prepare('INSERT INTO investissement_secteurs_inv (investissement_id, secteur_id) VALUES (?, ?)');
      for (const id of ids) ins.run(req.params.id, id);
    })();
    res.json({ ok: true });
  } catch (e) { next(e); }
});

// ── Helpers sync ──────────────────────────────────────────────────────────

/**
 * Quand les catégories d'une plateforme changent, resynchronise tous
 * les investissements actifs de cette plateforme.
 * Appelé dans une transaction existante.
 */
export function syncInvestissementsCategories(platId, catIds) {
  const invs = db.prepare(
    "SELECT id FROM investissements WHERE plateforme_id = ? AND statut NOT IN ('rembourse','cloture')"
  ).all(platId);
  const del = db.prepare('DELETE FROM investissement_categories_inv WHERE investissement_id = ?');
  const ins = db.prepare('INSERT OR IGNORE INTO investissement_categories_inv (investissement_id, categorie_id) VALUES (?, ?)');
  for (const { id } of invs) {
    del.run(id);
    for (const catId of catIds) ins.run(id, catId);
  }
}

export function syncInvestissementsSecteurs(platId, sectIds) {
  const invs = db.prepare(
    "SELECT id FROM investissements WHERE plateforme_id = ? AND statut NOT IN ('rembourse','cloture')"
  ).all(platId);
  const del = db.prepare('DELETE FROM investissement_secteurs_inv WHERE investissement_id = ?');
  const ins = db.prepare('INSERT OR IGNORE INTO investissement_secteurs_inv (investissement_id, secteur_id) VALUES (?, ?)');
  for (const { id } of invs) {
    del.run(id);
    for (const sectId of sectIds) ins.run(id, sectId);
  }
}

export default router;
