const jwtConfig = require('../config/jwt');
const authService = require('../services/authService');
const rateLimit = require('express-rate-limit');

// JWT Authentication Middleware
const authenticateToken = async (req, res, next) => {
  try {
    const authHeader = req.headers.authorization;
    
    if (!authHeader) {
      return res.status(401).json({
        success: false,
        error: 'Access token required',
        message: 'Authorization header missing'
      });
    }
    
    const token = jwtConfig.extractTokenFromHeader(authHeader);
    const user = await authService.verifyAccessToken(token);
    
    // Attach user to request
    req.user = user;
    req.token = token;
    
    next();
  } catch (error) {
    console.error('🔐 Authentication failed:', error.message);
    
    return res.status(401).json({
      success: false,
      error: 'Invalid access token',
      message: error.message
    });
  }
};

// Optional Authentication (doesn't fail if no token)
const optionalAuth = async (req, res, next) => {
  try {
    const authHeader = req.headers.authorization;
    
    if (authHeader) {
      const token = jwtConfig.extractTokenFromHeader(authHeader);
      const user = await authService.verifyAccessToken(token);
      req.user = user;
      req.token = token;
    }
    
    next();
  } catch (error) {
    // Continue without authentication for optional auth
    console.warn('⚠️ Optional auth failed:', error.message);
    next();
  }
};

// Role-based Authorization Middleware
const requireRole = (roles) => {
  return (req, res, next) => {
    if (!req.user) {
      return res.status(401).json({
        success: false,
        error: 'Authentication required',
        message: 'User not authenticated'
      });
    }
    
    const userRole = req.user.role;
    const allowedRoles = Array.isArray(roles) ? roles : [roles];
    
    if (!allowedRoles.includes(userRole)) {
      return res.status(403).json({
        success: false,
        error: 'Insufficient permissions',
        message: `Role '${userRole}' is not authorized. Required: ${allowedRoles.join(', ')}`
      });
    }
    
    next();
  };
};

// Admin-only middleware
const requireAdmin = requireRole(['admin']);

// User or Admin middleware
const requireUserOrAdmin = requireRole(['user', 'admin']);

// Rate Limiting Middleware (disabled by default via env)
const isAuthRateLimitDisabled = (process.env.AUTH_DISABLE_RATE_LIMIT || process.env.DISABLE_RATE_LIMIT || 'true').toLowerCase() === 'true';
const createRateLimit = (windowMs, max, message) => {
  if (isAuthRateLimitDisabled) {
    return (req, res, next) => next();
  }
  return rateLimit({
    windowMs,
    max,
    message: {
      success: false,
      error: 'Rate limit exceeded',
      message,
      retryAfter: Math.ceil(windowMs / 1000)
    },
    standardHeaders: true,
    legacyHeaders: false,
    // Custom key generator based on IP and user ID
    keyGenerator: (req) => {
      return req.user ? `${req.ip}-${req.user.id}` : req.ip;
    }
  });
};

// Specific rate limiters
const loginRateLimit = createRateLimit(
  15 * 60 * 1000, // 15 minutes
  10000, // 5 attempts
  'Too many login attempts. Please try again.'
);

const registerRateLimit = createRateLimit(
  60 * 60 * 1000, // 1 hour
  10000, // 3 registrations
  'Too many registration attempts. Please try again in 1 hour.'
);

const passwordChangeRateLimit = createRateLimit(
  60 * 60 * 1000, // 1 hour
  10000, // 3 password changes
  'Too many password change attempts. Please try again in 1 hour.'
);

// const apiRateLimit = createRateLimit(
//   15 * 60 * 1000, // 15 minutes
//   1000000, // 100 requests
//   'Too many API requests. Please slow down.'
// );

// Session Validation Middleware
const validateSession = async (req, res, next) => {
  try {
    const sessionToken = req.headers['x-session-token'] || req.cookies.sessionToken;
    
    if (sessionToken && req.user) {
      // Update session activity
      await authService.updateSessionActivity(sessionToken);
    }
    
    next();
  } catch (error) {
    console.warn('⚠️ Session validation failed:', error.message);
    next(); // Continue even if session update fails
  }
};

// Request Logging Middleware
const logAuthRequests = (req, res, next) => {
  const start = Date.now();
  
  // Log request
  console.log(`🔐 ${req.method} ${req.originalUrl} - ${req.ip} - ${req.user ? req.user.email : 'anonymous'}`);
  
  // Log response
  const originalSend = res.send;
  res.send = function(data) {
    const duration = Date.now() - start;
    const statusColor = res.statusCode >= 400 ? '❌' : '✅';
    console.log(`${statusColor} ${res.statusCode} - ${duration}ms`);
    originalSend.call(this, data);
  };
  
  next();
};

// Validate User Ownership (for user-specific resources)
const validateOwnership = (req, res, next) => {
  const userId = req.params.userId || req.params.id;
  const requestingUserId = req.user.id;
  const userRole = req.user.role;
  
  // Admin can access any user's resources
  if (userRole === 'admin') {
    return next();
  }
  
  // Users can only access their own resources
  if (userId && userId !== requestingUserId) {
    return res.status(403).json({
      success: false,
      error: 'Access denied',
      message: 'You can only access your own resources'
    });
  }
  
  next();
};

// Input Validation Middleware
const validateRegistration = (req, res, next) => {
  const { username, email, password, first_name, last_name } = req.body;
  
  const errors = [];
  
  if (!username || username.length < 3) {
    errors.push('Username must be at least 3 characters long');
  }
  
  if (!/^[a-zA-Z0-9_]+$/.test(username)) {
    errors.push('Username can only contain letters, numbers, and underscores');
  }
  
  if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
    errors.push('Valid email is required');
  }
  
  if (!password || password.length < 8) {
    errors.push('Password must be at least 8 characters long');
  }
  
  if (!first_name || first_name.trim().length === 0) {
    errors.push('First name is required');
  }
  
  if (!last_name || last_name.trim().length === 0) {
    errors.push('Last name is required');
  }
  
  if (errors.length > 0) {
    return res.status(400).json({
      success: false,
      error: 'Validation failed',
      message: 'Please fix the following errors',
      details: errors
    });
  }
  
  next();
};

const validateLogin = (req, res, next) => {
  const { email, password } = req.body;
  
  if (!email || !password) {
    return res.status(400).json({
      success: false,
      error: 'Validation failed',
      message: 'Email and password are required'
    });
  }
  
  next();
};

// Security Headers Middleware
const securityHeaders = (req, res, next) => {
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('X-XSS-Protection', '1; mode=block');
  res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
  
  next();
};

// Error Handler Middleware
const authErrorHandler = (error, req, res, next) => {
  console.error('🔐 Auth Error:', error);
  
  // JWT specific errors
  if (error.name === 'JsonWebTokenError') {
    return res.status(401).json({
      success: false,
      error: 'Invalid token',
      message: 'The provided token is malformed'
    });
  }
  
  if (error.name === 'TokenExpiredError') {
    return res.status(401).json({
      success: false,
      error: 'Token expired',
      message: 'Please refresh your token'
    });
  }
  
  // Database errors
  if (error.code === '23505') {
    return res.status(409).json({
      success: false,
      error: 'Conflict',
      message: 'Resource already exists'
    });
  }
  
  // Default error
  res.status(500).json({
    success: false,
    error: 'Internal server error',
    message: process.env.NODE_ENV === 'development' ? error.message : 'Something went wrong'
  });
};

module.exports = {
  authenticateToken,
  optionalAuth,
  requireRole,
  requireAdmin,
  requireUserOrAdmin,
  loginRateLimit,
  registerRateLimit,
  passwordChangeRateLimit,
  // apiRateLimit,
  validateSession,
  logAuthRequests,
  validateOwnership,
  validateRegistration,
  validateLogin,
  securityHeaders,
  authErrorHandler
};