const jwt = require('jsonwebtoken');
const logger = require('../utils/logger');
const db = require('../database/db').db;
const { SESSION_POLICY } = require('../utils/passwordPolicy');

const JWT_SECRET = process.env.JWT_SECRET || 'change_this_in_production';

const authenticate = (req, res, next) => {
  // Check Authorization header first, then query parameter
  let token = req.headers.authorization?.split(' ')[1];
  
  if (!token && req.query.token) {
    token = req.query.token;
  }

  if (!token) {
    logger.info('[AUTH] No token provided');
    return res.status(401).json({ error: 'Authentication required' });
  }

  // CWE-532: Do not log tokens or token details - they are credentials
  logger.info('[AUTH] Verifying authentication token');
  
  try {
    const decoded = jwt.verify(token, JWT_SECRET);
    logger.info(`[AUTH] Token verified for user ${decoded.userId}`);
    
    // Check session activity and idle timeout
    db.get(
      'SELECT * FROM active_sessions WHERE session_token = ? AND user_id = ?',
      [token, decoded.userId],
      (err, session) => {
        if (err) {
          logger.error('Session check error:', err);
          return res.status(500).json({ error: 'Session validation failed' });
        }

        if (!session) {
          logger.info('[AUTH] Session not found for token in database');
          return res.status(401).json({ error: 'Session not found or expired', sessionExpired: true });
        }
        
        logger.info('[AUTH] Session found, checking expiry');

        // Check if session has expired (absolute timeout)
        const now = new Date();
        const expiresAt = new Date(session.expires_at);
        
        if (now >= expiresAt) {
          // Delete expired session
          db.run('DELETE FROM active_sessions WHERE id = ?', [session.id]);
          return res.status(401).json({ error: 'Session expired', sessionExpired: true });
        }

        // Check idle timeout (2 hours by default)
        const lastActivity = new Date(session.last_activity);
        const idleTimeMs = now - lastActivity;
        const idleTimeoutMs = SESSION_POLICY.idleTimeout * 60 * 60 * 1000; // Convert hours to ms
        
        if (idleTimeMs > idleTimeoutMs) {
          // Session idle for too long - terminate it
          db.run('DELETE FROM active_sessions WHERE id = ?', [session.id]);
          logger.info(`Session ${session.id} terminated due to idle timeout (${idleTimeMs}ms idle)`);
          return res.status(401).json({ error: 'Session expired due to inactivity', sessionExpired: true });
        }

        // Update last activity
        db.run(
          'UPDATE active_sessions SET last_activity = ? WHERE id = ?',
          [now.toISOString(), session.id],
          (updateErr) => {
            if (updateErr) {
              logger.error('Failed to update session activity:', updateErr);
            }
          }
        );

        req.user = decoded;
        req.sessionId = session.id;
        next();
      }
    );
  } catch (error) {
    logger.error('Authentication error:', error);
    logger.error(`[AUTH] JWT Verification Failed: ${error.name} - ${error.message}`);
    
    // Provide more specific error messages
    let errorMessage = 'Invalid or expired token';
    if (error.name === 'TokenExpiredError') {
      errorMessage = 'Token has expired';
    } else if (error.name === 'JsonWebTokenError') {
      errorMessage = 'Invalid token';
    }
    
    res.status(401).json({ 
      error: errorMessage,
      sessionExpired: true // This triggers automatic logout on frontend
    });
  }
};

const authorize = (...roles) => {
  return (req, res, next) => {
    if (!req.user) {
      return res.status(401).json({ error: 'Authentication required' });
    }

    if (!roles.includes(req.user.role)) {
      return res.status(403).json({ error: 'Insufficient permissions' });
    }

    next();
  };
};

// Convenience middleware for admin-only routes
const requireAdmin = (req, res, next) => {
  if (!req.user) {
    return res.status(401).json({ error: 'Authentication required' });
  }
  
  if (req.user.role !== 'admin') {
    return res.status(403).json({ error: 'Admin access required' });
  }
  
  next();
};

module.exports = { authenticate, authorize, requireAdmin };
