import type { FastifyInstance } from 'fastify';
import { BadRequestError, ForbiddenError, UnauthorizedError } from '../../lib/errors.js';
import * as repo from './repository.js';

export async function sessionRoutes(app: FastifyInstance) {
  // ── User endpoints (authenticated) ─────────────────────────

  // List my active sessions
  app.get('/sessions', async req => {
    const payload = req.jwtPayload;
    if (!payload?.sub) throw new UnauthorizedError('Authentication required');

    const sessions = await repo.listUserSessions(payload.sub);
    return {
      sessions: sessions.map(stripSensitive),
      count: sessions.length,
    };
  });

  // Revoke a specific session
  app.delete('/sessions/:id', async req => {
    const payload = req.jwtPayload;
    if (!payload?.sub) throw new UnauthorizedError('Authentication required');

    const { id } = req.params as { id: string };
    const revoked = await repo.revokeSession(id, payload.sub);
    if (!revoked) throw new BadRequestError('Session not found or already revoked');

    req.log.info({ sessionId: id, userId: payload.sub }, '[sessions] Session revoked');
    return { success: true };
  });

  // Revoke all my sessions (sign out everywhere)
  app.delete('/sessions', async req => {
    const payload = req.jwtPayload;
    if (!payload?.sub) throw new UnauthorizedError('Authentication required');

    const count = await repo.revokeAllUserSessions(payload.sub);
    req.log.info({ userId: payload.sub, count }, '[sessions] All sessions revoked');
    return { success: true, revokedCount: count };
  });

  // ── Admin endpoints ────────────────────────────────────────

  function requireAdmin(req: import('fastify').FastifyRequest): void {
    const role = req.jwtPayload?.role;
    if (!role || !['super_admin', 'admin'].includes(role)) {
      throw new ForbiddenError('Admin access required');
    }
  }

  // Admin: list a user's sessions (active + revoked)
  app.get('/sessions/user/:userId', async req => {
    requireAdmin(req);
    const { userId } = req.params as { userId: string };
    const sessions = await repo.listAllUserSessions(userId);
    return {
      sessions: sessions.map(stripSensitive),
      count: sessions.length,
    };
  });

  // Admin: force-revoke all sessions for a user
  app.delete('/sessions/user/:userId', async req => {
    requireAdmin(req);
    const { userId } = req.params as { userId: string };
    const count = await repo.revokeAllUserSessions(userId);

    req.log.info(
      { userId, adminId: req.jwtPayload?.sub, count },
      '[sessions] Admin force-revoked all sessions'
    );
    return { success: true, revokedCount: count };
  });
}

// Strip internal fields from response
function stripSensitive(session: import('./types.js').SessionDoc) {
  const { _ts, _etag, ...rest } = session;
  void _ts;
  void _etag;
  return rest;
}
