/**
 * Session Management Routes
 * Handles active session viewing, management, and termination
 */

const express = require('express');
const router = express.Router();
const { authenticate, requireAdmin } = require('../middleware/auth');
const { readLimiter, modifyLimiter } = require('../middleware/rateLimiter');
const { db } = require('../database/db');
const logger = require('../utils/logger');
const SecurityAuditLogger = require('../utils/securityAudit');

/**
 * Get all active sessions for current user
 */
router.get('/my-sessions', authenticate, readLimiter, async (req, res) => {
  try {
    const userId = req.user.userId;
    const currentToken = req.headers.authorization?.split(' ')[1];

    db.all(
      `SELECT 
        id,
        session_token,
        ip_address,
        user_agent,
        created_at,
        last_activity,
        expires_at
       FROM active_sessions 
       WHERE user_id = ? AND expires_at > ?
       ORDER BY last_activity DESC`,
      [userId, new Date().toISOString()],
      (err, sessions) => {
        if (err) {
          logger.error('Error fetching sessions:', err);
          return res.status(500).json({ error: 'Failed to fetch sessions' });
        }

        // Mark current session
        const sessionsWithCurrent = sessions.map(session => ({
          ...session,
          isCurrent: session.session_token === currentToken,
          // Don't expose full token to client
          session_token: undefined
        }));

        res.json(sessionsWithCurrent);
      }
    );
  } catch (error) {
    logger.error('Session fetch error:', error);
    res.status(500).json({ error: 'Failed to fetch sessions' });
  }
});

/**
 * Get all active sessions (admin only)
 */
router.get('/all', authenticate, requireAdmin, readLimiter, async (req, res) => {
  try {
    db.all(
      `SELECT 
        s.id,
        s.user_id,
        s.ip_address,
        s.user_agent,
        s.created_at,
        s.last_activity,
        s.expires_at,
        u.username,
        u.email
       FROM active_sessions s
       JOIN users u ON s.user_id = u.id
       WHERE s.expires_at > ?
       ORDER BY s.last_activity DESC`,
      [new Date().toISOString()],
      (err, sessions) => {
        if (err) {
          logger.error('Error fetching all sessions:', err);
          return res.status(500).json({ error: 'Failed to fetch sessions' });
        }

        res.json(sessions);
      }
    );
  } catch (error) {
    logger.error('Session fetch error:', error);
    res.status(500).json({ error: 'Failed to fetch sessions' });
  }
});

/**
 * Terminate a specific session
 */
router.delete('/:sessionId', authenticate, modifyLimiter, async (req, res) => {
  try {
    const { sessionId } = req.params;
    const userId = req.user.userId;
    const currentToken = req.headers.authorization?.split(' ')[1];

    // Validate session ID
    if (isNaN(parseInt(sessionId))) {
      return res.status(400).json({ error: 'Invalid session ID' });
    }

    // Get session details first
    db.get(
      'SELECT * FROM active_sessions WHERE id = ?',
      [sessionId],
      async (err, session) => {
        if (err) {
          logger.error('Error fetching session:', err);
          return res.status(500).json({ error: 'Failed to terminate session' });
        }

        if (!session) {
          return res.status(404).json({ error: 'Session not found' });
        }

        // Only allow users to terminate their own sessions (or admins to terminate any)
        if (session.user_id !== userId && req.user.role !== 'admin') {
          return res.status(403).json({ error: 'Permission denied' });
        }

        // Prevent terminating current session
        if (session.session_token === currentToken) {
          return res.status(400).json({ error: 'Cannot terminate current session. Use logout instead.' });
        }

        // Terminate session
        db.run(
          'DELETE FROM active_sessions WHERE id = ?',
          [sessionId],
          async (err) => {
            if (err) {
              logger.error('Error terminating session:', err);
              return res.status(500).json({ error: 'Failed to terminate session' });
            }

            // Log the event
            await SecurityAuditLogger.logSessionEvent('SESSION_TERMINATED', userId, {
              ip: req.ip || req.headers['x-forwarded-for'],
              userAgent: req.headers['user-agent'],
              sessionId: sessionId,
              terminatedSessionIp: session.ip_address
            });

            logger.info(`Session ${sessionId} terminated by user ${userId}`);
            res.json({ message: 'Session terminated successfully' });
          }
        );
      }
    );
  } catch (error) {
    logger.error('Session termination error:', error);
    res.status(500).json({ error: 'Failed to terminate session' });
  }
});

/**
 * Terminate all other sessions (keep current)
 */
router.post('/terminate-all-others', authenticate, modifyLimiter, async (req, res) => {
  try {
    const userId = req.user.userId;
    const currentToken = req.headers.authorization?.split(' ')[1];

    db.run(
      'DELETE FROM active_sessions WHERE user_id = ? AND session_token != ?',
      [userId, currentToken],
      async function(err) {
        if (err) {
          logger.error('Error terminating sessions:', err);
          return res.status(500).json({ error: 'Failed to terminate sessions' });
        }

        const terminatedCount = this.changes;

        // Log the event
        await SecurityAuditLogger.logSessionEvent('SESSIONS_TERMINATED_BULK', userId, {
          ip: req.ip || req.headers['x-forwarded-for'],
          userAgent: req.headers['user-agent'],
          count: terminatedCount
        });

        logger.info(`User ${userId} terminated ${terminatedCount} other sessions`);
        res.json({ 
          message: `${terminatedCount} session(s) terminated successfully`,
          count: terminatedCount
        });
      }
    );
  } catch (error) {
    logger.error('Bulk session termination error:', error);
    res.status(500).json({ error: 'Failed to terminate sessions' });
  }
});

/**
 * Force logout user (admin only) - terminates all sessions
 */
router.post('/force-logout/:userId', authenticate, requireAdmin, modifyLimiter, async (req, res) => {
  try {
    const { userId } = req.params;

    // Validate user ID
    if (isNaN(parseInt(userId))) {
      return res.status(400).json({ error: 'Invalid user ID' });
    }

    // Get user info
    db.get(
      'SELECT username FROM users WHERE id = ?',
      [userId],
      async (err, user) => {
        if (err || !user) {
          return res.status(404).json({ error: 'User not found' });
        }

        // Terminate all sessions for this user
        db.run(
          'DELETE FROM active_sessions WHERE user_id = ?',
          [userId],
          async function(err) {
            if (err) {
              logger.error('Error force logging out user:', err);
              return res.status(500).json({ error: 'Failed to force logout' });
            }

            const terminatedCount = this.changes;

            // Log the event
            await SecurityAuditLogger.logSessionEvent('FORCE_LOGOUT', userId, {
              ip: req.ip || req.headers['x-forwarded-for'],
              userAgent: req.headers['user-agent'],
              adminId: req.user.userId,
              count: terminatedCount
            });

            logger.warn(`Admin ${req.user.userId} force logged out user ${userId} (${user.username}), terminated ${terminatedCount} sessions`);
            res.json({ 
              message: `User ${user.username} has been logged out`,
              count: terminatedCount
            });
          }
        );
      }
    );
  } catch (error) {
    logger.error('Force logout error:', error);
    res.status(500).json({ error: 'Failed to force logout' });
  }
});

/**
 * Get session statistics (admin only)
 */
router.get('/stats', authenticate, requireAdmin, readLimiter, async (req, res) => {
  try {
    const now = new Date().toISOString();

    // Total active sessions
    db.get(
      'SELECT COUNT(*) as total FROM active_sessions WHERE expires_at > ?',
      [now],
      (err, totalResult) => {
        if (err) {
          logger.error('Error fetching session stats:', err);
          return res.status(500).json({ error: 'Failed to fetch statistics' });
        }

        // Sessions by user
        db.all(
          `SELECT u.username, u.email, COUNT(s.id) as session_count
           FROM users u
           LEFT JOIN active_sessions s ON u.id = s.user_id AND s.expires_at > ?
           GROUP BY u.id
           ORDER BY session_count DESC
           LIMIT 10`,
          [now],
          (err, userSessions) => {
            if (err) {
              logger.error('Error fetching user sessions:', err);
              return res.status(500).json({ error: 'Failed to fetch statistics' });
            }

            // Recent sessions
            db.all(
              `SELECT s.*, u.username
               FROM active_sessions s
               JOIN users u ON s.user_id = u.id
               WHERE s.expires_at > ?
               ORDER BY s.created_at DESC
               LIMIT 20`,
              [now],
              (err, recentSessions) => {
                if (err) {
                  logger.error('Error fetching recent sessions:', err);
                  return res.status(500).json({ error: 'Failed to fetch statistics' });
                }

                res.json({
                  totalActiveSessions: totalResult.total,
                  topUsers: userSessions.filter(u => u.session_count > 0),
                  recentSessions: recentSessions.map(s => ({
                    username: s.username,
                    ip: s.ip_address,
                    created: s.created_at,
                    lastActive: s.last_activity
                  }))
                });
              }
            );
          }
        );
      }
    );
  } catch (error) {
    logger.error('Session stats error:', error);
    res.status(500).json({ error: 'Failed to fetch statistics' });
  }
});

module.exports = router;
