import { Router, type Request } from 'express';
import { rateLimit } from 'express-rate-limit';
import type { AppEnv } from '../config/env.js';
import type { AuthService } from '../services/auth-service.js';
import { auditContext, csrfProtection, requireAuth, setFlash } from './middleware.js';

function regenerateSession(req: Request): Promise<void> {
  return new Promise((resolve, reject) => req.session.regenerate((error: Error | null) => error ? reject(error) : resolve()));
}

export function authRoutes(auth: AuthService, env: AppEnv): Router {
  const router = Router();
  const loginLimiter = rateLimit({
    windowMs: env.LOGIN_WINDOW_MINUTES * 60_000,
    limit: env.LOGIN_MAX_ATTEMPTS,
    standardHeaders: 'draft-8',
    legacyHeaders: false,
    message: 'تعداد تلاش ورود بیش از حد مجاز است. کمی بعد دوباره تلاش کنید.'
  });

  router.get('/login', (req, res) => {
    if (req.currentUser) return res.redirect('/');
    res.render('auth/login', { title: 'ورود به سامانه', error: null });
  });

  router.post('/login', loginLimiter, csrfProtection, async (req, res, next) => {
    try {
      const user = await auth.authenticate(String(req.body.username ?? ''), String(req.body.password ?? ''), auditContext(req));
      if (!user) return res.status(422).render('auth/login', { title: 'ورود به سامانه', error: 'نام کاربری یا رمز عبور صحیح نیست.' });
      await regenerateSession(req);
      req.session.userId = user.id;
      req.session.sessionVersion = user.sessionVersion;
      delete req.session.csrfToken;
      res.redirect(user.forcePasswordChange ? '/password/force' : '/');
    } catch (error) { next(error); }
  });

  router.get('/password/force', requireAuth, (req, res) => {
    res.render('auth/force-password', { title: 'تغییر اجباری رمز عبور', error: null });
  });

  router.post('/password/force', requireAuth, csrfProtection, async (req, res, next) => {
    try {
      const current = String(req.body.currentPassword ?? '');
      const password = String(req.body.password ?? '');
      if (password !== String(req.body.passwordConfirmation ?? '')) {
        return res.status(422).render('auth/force-password', { title: 'تغییر اجباری رمز عبور', error: 'تکرار رمز عبور با رمز جدید یکسان نیست.' });
      }
      const version = await auth.changeOwnPassword(req.currentUser!.id, current, password, auditContext(req));
      req.session.sessionVersion = version;
      setFlash(req, 'success', 'رمز عبور با موفقیت تغییر کرد.');
      res.redirect('/');
    } catch (error) { next(error); }
  });

  router.get('/profile', requireAuth, (req, res) => res.render('auth/profile', { title: 'پروفایل و امنیت', error: null }));
  router.post('/profile/password', requireAuth, csrfProtection, async (req, res, next) => {
    try {
      const password = String(req.body.password ?? '');
      if (password !== String(req.body.passwordConfirmation ?? '')) throw new Error('تکرار رمز عبور با رمز جدید یکسان نیست.');
      const version = await auth.changeOwnPassword(req.currentUser!.id, String(req.body.currentPassword ?? ''), password, auditContext(req));
      req.session.sessionVersion = version;
      setFlash(req, 'success', 'رمز عبور با موفقیت تغییر کرد.');
      res.redirect('/profile');
    } catch (error) { next(error); }
  });

  router.post('/logout', csrfProtection, (req, res) => {
    req.session.destroy(() => res.redirect('/login'));
  });
  return router;
}
