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

export const authRouter = Router();

const loginSchema = z.object({
  username: z.string().min(1),
  password: z.string().min(1),
});

authRouter.post("/login", async (req, res) => {
  const parsed = loginSchema.safeParse(req.body);
  if (!parsed.success) {
    return res.status(400).json({ error: "Champs invalides" });
  }
  const { username, password } = parsed.data;

  const user = await prisma.user.findUnique({ where: { username } });
  if (!user || !user.isActive) {
    await recordLogin(req, { username, success: false, userId: user?.id ?? null });
    return res.status(401).json({ error: "Identifiants incorrects" });
  }
  const ok = await verifyPassword(password, user.passwordHash);
  if (!ok) {
    await recordLogin(req, { username, success: false, userId: user.id });
    return res.status(401).json({ error: "Identifiants incorrects" });
  }

  const accessToken = signAccessToken({
    sub: user.id,
    username: user.username,
    role: user.role,
  });
  const refreshToken = signRefreshToken(user.id);
  setSessionCookies(res, accessToken, refreshToken);
  await recordLogin(req, { username: user.username, userId: user.id, success: true });

  return res.json({
    user: { id: user.id, username: user.username, role: user.role, displayName: user.displayName },
  });
});

authRouter.post("/refresh", async (req, res) => {
  const token = req.cookies?.refresh_token;
  if (!token) return res.status(401).json({ error: "Non authentifié" });
  try {
    const { sub, imp } = verifyRefreshToken(token);
    const user = await prisma.user.findUnique({ where: { id: sub } });
    if (!user || !user.isActive) return res.status(401).json({ error: "Compte indisponible" });

    const accessToken = signAccessToken({
      sub: user.id,
      username: user.username,
      role: user.role,
      ...(imp ? { imp } : {}),
    });
    setAccessCookie(res, accessToken);
    return res.json({ ok: true });
  } catch {
    return res.status(401).json({ error: "Session expirée" });
  }
});

authRouter.get("/me", requireAuth, async (req, res) => {
  const user = await prisma.user.findUnique({ where: { id: req.user!.sub } });
  if (!user) return res.status(404).json({ error: "Utilisateur introuvable" });
  return res.json({
    user: { id: user.id, username: user.username, role: user.role, displayName: user.displayName },
    impersonating: Boolean(req.user!.imp),
  });
});

authRouter.post("/logout", (_req, res) => {
  clearSessionCookies(res);
  return res.json({ ok: true });
});

// Revenir à son compte Super Admin après une impersonation.
authRouter.post("/stop-impersonation", requireAuth, async (req, res) => {
  const impId = req.user!.imp;
  if (!impId) return res.status(400).json({ error: "Pas en mode impersonation" });

  const admin = await prisma.user.findUnique({ where: { id: impId } });
  if (!admin || !admin.isActive) return res.status(401).json({ error: "Compte indisponible" });

  const accessToken = signAccessToken({ sub: admin.id, username: admin.username, role: admin.role });
  const refreshToken = signRefreshToken(admin.id);
  setSessionCookies(res, accessToken, refreshToken);

  return res.json({
    user: { id: admin.id, username: admin.username, role: admin.role, displayName: admin.displayName },
  });
});

const passwordSchema = z.object({
  currentPassword: z.string().min(1),
  newPassword: z.string().min(8),
});

// Changement de son propre mot de passe.
authRouter.post("/password", requireAuth, async (req, res) => {
  const parsed = passwordSchema.safeParse(req.body);
  if (!parsed.success) {
    return res.status(400).json({ error: "Le nouveau mot de passe doit faire au moins 8 caractères" });
  }
  const { currentPassword, newPassword } = parsed.data;

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

  const ok = await verifyPassword(currentPassword, user.passwordHash);
  if (!ok) return res.status(401).json({ error: "Mot de passe actuel incorrect" });

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