/** مسیرهای احراز هویت */
import type { FastifyInstance } from 'fastify';
import { z } from 'zod';
import { config } from '../../config/index.js';
import { login, logout, register, rotateSession } from '../../modules/auth/service.js';
import { assignRole, effectivePermissions, loadGrants } from '../../modules/rbac/service.js';
import { requireAuth } from '../../guards/index.js';
import { recordAudit, AuditActions } from '../../modules/audit/service.js';

const credentials = z.object({ email: z.string().email('ایمیل نامعتبر است.'), password: z.string().min(8, 'گذرواژه کوتاه است.') });

function setSessionCookies(reply: any, token: string, csrfToken: string, expiresAt: Date) {
  const base = { path: '/', sameSite: 'lax' as const, secure: config.security.cookieSecure, expires: expiresAt };
  // کوکی نشست HttpOnly است تا در برابر XSS محافظت شود
  reply.setCookie(config.security.cookieName, token, { ...base, httpOnly: true });
  // کوکی CSRF عمداً قابل خواندن است (الگوی Double Submit)
  reply.setCookie(config.security.csrfCookieName, csrfToken, { ...base, httpOnly: false });
}

export default async function authRoutes(app: FastifyInstance) {
  app.post('/register', { config: { rateLimit: { max: 5, timeWindow: '10 minutes' } } }, async (req, reply) => {
    const body = credentials.extend({ displayName: z.string().min(2), phone: z.string().optional() }).parse(req.body);
    const user = await register(body);
    await assignRole(user.id, 'citizen');
    const session = await login(body.email, body.password, { ip: req.ip, userAgent: req.headers['user-agent'] });
    setSessionCookies(reply, session.token, session.csrfToken, session.expiresAt);
    return { user: { id: user.id, displayName: user.displayName, email: user.email }, permissions: [] };
  });

  app.post('/login', { config: { rateLimit: { max: 10, timeWindow: '5 minutes' } } }, async (req, reply) => {
    const body = credentials.parse(req.body);
    const result = await login(body.email, body.password, { ip: req.ip, userAgent: req.headers['user-agent'] });
    setSessionCookies(reply, result.token, result.csrfToken, result.expiresAt);
    const grants = await loadGrants(result.user.id);
    return {
      user: { id: result.user.id, displayName: result.user.displayName, email: result.user.email },
      roles: grants.map((g) => ({ role: g.roleKey, scopeType: g.scopeType, scopeId: g.scopeId })),
      permissions: effectivePermissions({ userId: result.user.id, displayName: '', email: '', grants }),
    };
  });

  app.post('/logout', async (req, reply) => {
    if (req.sessionToken) {
      await logout(req.sessionToken);
      await recordAudit({ action: AuditActions.LOGOUT, actorId: req.principal?.userId ?? null, ip: req.ip });
    }
    reply.clearCookie(config.security.cookieName, { path: '/' });
    reply.clearCookie(config.security.csrfCookieName, { path: '/' });
    return { ok: true };
  });

  /** چرخش توکن نشست */
  app.post('/refresh', async (req, reply) => {
    requireAuth(req);
    const rotated = await rotateSession(req.sessionToken!, { ip: req.ip, userAgent: req.headers['user-agent'] });
    setSessionCookies(reply, rotated.token, rotated.csrfToken, rotated.expiresAt);
    return { ok: true };
  });

  app.get('/me', async (req) => {
    if (!req.principal) return { authenticated: false };
    return {
      authenticated: true,
      user: { id: req.principal.userId, displayName: req.principal.displayName, email: req.principal.email },
      roles: req.principal.grants.map((g) => ({ role: g.roleKey, scopeType: g.scopeType, scopeId: g.scopeId })),
      permissions: effectivePermissions(req.principal),
    };
  });
}
