/**
 * Interface d'administration maison — remplace l'admin Django.
 * Un moteur générique (liste + formulaire) piloté par src/admin/resources.js,
 * plutôt qu'une dépendance tierce dont je ne pouvais pas vérifier
 * l'installation dans cet environnement. Auth par session, upload
 * d'images via multer.
 */
const express = require("express");
const session = require("express-session");
const SequelizeStore = require("connect-session-sequelize")(session.Store);
const multer = require("multer");
const path = require("path");
const fs = require("fs");

const sequelize = require("../config/database");
const resources = require("./resources");
const { indexKnowledgeItem } = require("../services/chatbotService");

const router = express.Router();
const MEDIA_ROOT = path.join(__dirname, "..", "..", "media");

// --- Session ----------------------------------------------------------
const sessionStore = new SequelizeStore({ db: sequelize, tableName: "admin_sessions" });
router.use(session({
  store: sessionStore,
  secret: process.env.SESSION_SECRET || "change-me",
  resave: false,
  saveUninitialized: false,
  cookie: { maxAge: 8 * 60 * 60 * 1000 }, // 8h
}));
sessionStore.sync();

router.use(express.urlencoded({ extended: true }));

// --- Upload (multer) -----------------------------------------------------
const upload = multer({
  storage: multer.diskStorage({
    destination: (req, file, cb) => {
      const dir = path.join(MEDIA_ROOT, req.params.resource || "misc");
      fs.mkdirSync(dir, { recursive: true });
      cb(null, dir);
    },
    filename: (req, file, cb) => {
      const safe = `${Date.now()}-${file.originalname.replace(/[^a-zA-Z0-9._-]/g, "_")}`;
      cb(null, safe);
    },
  }),
  limits: { fileSize: 8 * 1024 * 1024 },
});

// --- Auth ----------------------------------------------------------------
function requireAuth(req, res, next) {
  if (req.session.isAdmin) return next();
  res.redirect("/admin/login");
}

router.get("/login", (req, res) => {
  res.render("admin/login", { error: null });
});

router.post("/login", async (req, res) => {
  const { email, password } = req.body;
  const expectedEmail = process.env.ADMIN_EMAIL || "admin@igf.bi";
  const expectedPassword = process.env.ADMIN_PASSWORD || "";
  const validEmail = email === expectedEmail;
  const validPassword = password === expectedPassword; // comparaison directe, cf. note README sur le hachage
  if (validEmail && validPassword) {
    req.session.isAdmin = true;
    return res.redirect("/admin");
  }
  res.render("admin/login", { error: "Identifiants incorrects." });
});

router.post("/logout", requireAuth, (req, res) => {
  req.session.destroy(() => res.redirect("/admin/login"));
});

router.use(requireAuth);

function buildGroups() {
  const groups = {};
  for (const [key, conf] of Object.entries(resources)) {
    groups[conf.group] = groups[conf.group] || [];
    groups[conf.group].push({ key, label: conf.label });
  }
  return groups;
}

// --- Tableau de bord -----------------------------------------------------
router.get("/", (req, res) => {
  res.render("admin/dashboard", { groups: buildGroups() });
});

function getResourceOr404(req, res) {
  const conf = resources[req.params.resource];
  if (!conf) {
    res.status(404).send("Ressource inconnue.");
    return null;
  }
  return conf;
}

/** Construit la liste des champs réels (fr/en) à partir de la config déclarative. */
function expandFields(conf) {
  const expanded = [];
  for (const f of conf.fields) {
    if (f.translated) {
      expanded.push({ ...f, name: `${f.name}_fr`, dbName: `${f.name}_fr`, label: `${f.label} (FR)`, required: f.required });
      expanded.push({ ...f, name: `${f.name}_en`, dbName: `${f.name}_en`, label: `${f.label} (EN)`, required: false });
    } else {
      expanded.push({ ...f, dbName: f.name });
    }
  }
  return expanded;
}

// --- Liste ----------------------------------------------------------------
router.get("/:resource", async (req, res) => {
  const conf = getResourceOr404(req, res);
  if (!conf) return;
  const items = await conf.model.findAll({ order: [["id", "DESC"]], limit: 200 });
  res.render("admin/list", {
    resourceKey: req.params.resource,
    conf,
    items: items.map((i) => i.toJSON()),
    groups: buildGroups(),
  });
});

// --- Formulaire de création ------------------------------------------------
router.get("/:resource/new", async (req, res) => {
  const conf = getResourceOr404(req, res);
  if (!conf) return;
  const refOptions = await loadRefOptions(conf);
  res.render("admin/form", {
    resourceKey: req.params.resource, conf, item: {}, fields: expandFields(conf),
    refOptions, isNew: true, error: null, groups: buildGroups(),
  });
});

router.get("/:resource/:id/edit", async (req, res) => {
  const conf = getResourceOr404(req, res);
  if (!conf) return;
  const item = await conf.model.findByPk(req.params.id);
  if (!item) return res.status(404).send("Introuvable.");
  const refOptions = await loadRefOptions(conf);
  res.render("admin/form", {
    resourceKey: req.params.resource, conf, item: item.toJSON(), fields: expandFields(conf),
    refOptions, isNew: false, error: null, groups: buildGroups(),
  });
});

async function loadRefOptions(conf) {
  const out = {};
  for (const f of conf.fields) {
    if (f.type === "belongsTo") {
      const rows = await f.refModel.findAll({ order: [["id", "DESC"]], limit: 500 });
      out[f.name] = rows.map((r) => ({ id: r.id, label: r.get(f.refLabel) }));
    }
  }
  return out;
}

// --- Création / mise à jour -----------------------------------------------
router.post("/:resource", upload.any(), handleSave(false));
router.post("/:resource/:id", upload.any(), handleSave(true));

function handleSave(isUpdate) {
  return async (req, res) => {
    const conf = getResourceOr404(req, res);
    if (!conf) return;
    if (conf.readOnly) return res.status(403).send("Ressource en lecture seule.");

    const fields = expandFields(conf);
    const data = {};

    for (const f of fields) {
      if (f.type === "image") continue; // traité séparément via req.files
      if (f.type === "boolean") { data[f.dbName] = req.body[f.dbName] === "on"; continue; }
      if (f.type === "number") { data[f.dbName] = req.body[f.dbName] ? Number(req.body[f.dbName]) : null; continue; }
      if (f.type === "belongsTo") { data[f.dbName] = req.body[f.dbName] || null; continue; }
      data[f.dbName] = req.body[f.dbName] ?? "";
    }

    for (const file of req.files || []) {
      data[file.fieldname] = `/media/${req.params.resource}/${file.filename}`;
    }

    try {
      let instance;
      if (isUpdate) {
        instance = await conf.model.findByPk(req.params.id);
        if (!instance) return res.status(404).send("Introuvable.");
        await instance.update(data);
      } else {
        instance = await conf.model.create(data);
      }

      if (conf.reindexable) {
        indexKnowledgeItem(instance).catch((err) =>
          console.error("Échec de la réindexation du chatbot :", err.message)
        );
      }

      res.redirect(`/admin/${req.params.resource}`);
    } catch (err) {
      const refOptions = await loadRefOptions(conf);
      res.status(400).render("admin/form", {
        resourceKey: req.params.resource, conf, item: { ...req.body, id: req.params.id },
        fields, refOptions, isNew: !isUpdate, groups: buildGroups(),
        error: err.message || "Erreur lors de l'enregistrement.",
      });
    }
  };
}

// --- Suppression ------------------------------------------------------
router.post("/:resource/:id/delete", async (req, res) => {
  const conf = getResourceOr404(req, res);
  if (!conf) return;
  if (conf.readOnly) return res.status(403).send("Ressource en lecture seule.");
  await conf.model.destroy({ where: { id: req.params.id } });
  res.redirect(`/admin/${req.params.resource}`);
});

module.exports = router;
