import { Router } from "express";
import { z } from "zod";
import { prisma } from "../../lib/prisma";
import { hashPassword } from "../../lib/password";
import { signAccessToken, signRefreshToken } from "../../lib/jwt";
import { setSessionCookies } from "../../lib/session";
import { recordLogin } from "../../lib/audit";
import { requireAuth, requireCapability } from "../../middleware/auth";

export const usersRouter = Router();

// Toutes les routes : authentifié + capacité "users:manage" (super_admin uniquement).
usersRouter.use(requireAuth, requireCapability("users:manage"));

const roleEnum = z.enum(["super_admin", "admin", "user"]);

const publicUser = {
  id: true,
  username: true,
  email: true,
  role: true,
  displayName: true,
  isActive: true,
  createdAt: true,
  updatedAt: true,
} as const;

// Empêche de supprimer/rétrograder/désactiver le dernier super_admin (anti-verrouillage).
async function wouldRemoveLastSuperAdmin(userId: string): Promise<boolean> {
  const target = await prisma.user.findUnique({ where: { id: userId } });
  if (!target || target.role !== "super_admin") return false;
  const activeSuperAdmins = await prisma.user.count({
    where: { role: "super_admin", isActive: true },
  });
  return activeSuperAdmins <= 1;
}

usersRouter.get("/", async (_req, res) => {
  const users = await prisma.user.findMany({
    select: publicUser,
    orderBy: { createdAt: "asc" },
  });
  res.json({ users });
});

const createSchema = z.object({
  username: z.string().min(1).max(64),
  password: z.string().min(8),
  role: roleEnum.default("user"),
  displayName: z.string().max(128).optional(),
});

usersRouter.post("/", async (req, res) => {
  const parsed = createSchema.safeParse(req.body);
  if (!parsed.success) {
    return res.status(400).json({ error: "Champs invalides (mot de passe ≥ 8 caractères)" });
  }
  const { username, password, role, displayName } = parsed.data;

  const existing = await prisma.user.findUnique({ where: { username } });
  if (existing) {
    return res.status(409).json({ error: "Ce nom d'utilisateur existe déjà" });
  }

  const user = await prisma.user.create({
    data: {
      username,
      passwordHash: await hashPassword(password),
      role,
      displayName: displayName ?? null,
    },
    select: publicUser,
  });
  res.status(201).json({ user });
});

const updateSchema = z.object({
  role: roleEnum.optional(),
  displayName: z.string().max(128).nullable().optional(),
  isActive: z.boolean().optional(),
});

usersRouter.patch("/:id", async (req, res) => {
  const parsed = updateSchema.safeParse(req.body);
  if (!parsed.success) return res.status(400).json({ error: "Champs invalides" });
  const { id } = req.params;

  const target = await prisma.user.findUnique({ where: { id } });
  if (!target) return res.status(404).json({ error: "Utilisateur introuvable" });

  // Anti-verrouillage : ne pas retirer le rôle ou désactiver le dernier super_admin.
  const demoting = parsed.data.role !== undefined && parsed.data.role !== "super_admin";
  const deactivating = parsed.data.isActive === false;
  if ((demoting || deactivating) && (await wouldRemoveLastSuperAdmin(id))) {
    return res.status(409).json({ error: "Impossible : c'est le dernier super_admin actif" });
  }

  const user = await prisma.user.update({
    where: { id },
    data: parsed.data,
    select: publicUser,
  });
  res.json({ user });
});

const resetSchema = z.object({ password: z.string().min(8) });

usersRouter.post("/:id/password", async (req, res) => {
  const parsed = resetSchema.safeParse(req.body);
  if (!parsed.success) {
    return res.status(400).json({ error: "Mot de passe ≥ 8 caractères requis" });
  }
  const { id } = req.params;
  const target = await prisma.user.findUnique({ where: { id } });
  if (!target) return res.status(404).json({ error: "Utilisateur introuvable" });

  await prisma.user.update({
    where: { id },
    data: { passwordHash: await hashPassword(parsed.data.password) },
  });
  res.json({ ok: true });
});

usersRouter.delete("/:id", async (req, res) => {
  const { id } = req.params;
  const target = await prisma.user.findUnique({ where: { id } });
  if (!target) return res.status(404).json({ error: "Utilisateur introuvable" });

  if (id === req.user!.sub) {
    return res.status(409).json({ error: "Vous ne pouvez pas supprimer votre propre compte" });
  }
  if (await wouldRemoveLastSuperAdmin(id)) {
    return res.status(409).json({ error: "Impossible : c'est le dernier super_admin actif" });
  }

  await prisma.user.delete({ where: { id } });
  res.json({ ok: true });
});

// POST /users/:id/impersonate — le Super Admin ouvre une session "en tant que" cet utilisateur.
// Le jeton mémorise l'impersonateur (claim imp) pour pouvoir revenir via /auth/stop-impersonation.
usersRouter.post("/:id/impersonate", async (req, res) => {
  const id = String(req.params.id);
  // On refuse d'usurper en cascade (un compte déjà usurpé n'aurait de toute façon pas users:manage).
  if (req.user!.imp) return res.status(409).json({ error: "Déjà en mode impersonation" });
  if (id === req.user!.sub) return res.status(400).json({ error: "C'est déjà votre compte" });

  const target = await prisma.user.findUnique({ where: { id } });
  if (!target) return res.status(404).json({ error: "Utilisateur introuvable" });
  if (!target.isActive) return res.status(409).json({ error: "Compte désactivé" });

  const accessToken = signAccessToken({
    sub: target.id,
    username: target.username,
    role: target.role,
    imp: req.user!.sub,
  });
  const refreshToken = signRefreshToken(target.id, req.user!.sub);
  setSessionCookies(res, accessToken, refreshToken);
  await recordLogin(req, {
    username: target.username,
    userId: target.id,
    success: true,
    kind: "impersonation",
    actor: req.user!.username,
  });

  console.log(`[impersonation] ${req.user!.username} (${req.user!.sub}) → ${target.username} (${target.id})`);
  return res.json({
    user: { id: target.id, username: target.username, role: target.role, displayName: target.displayName },
  });
});
