const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const Joi = require('joi');
const { RateLimiterMemory } = require('rate-limiter-flexible');
const Player = require('../models/Player');
const logger = require('../utils/logger');

const router = express.Router();

// Rate limiting for auth routes
const authLimiter = new RateLimiterMemory({
  keyGenerator: (req) => req.ip,
  points: 5, // Number of requests
  duration: 900, // Per 15 minutes (900 seconds)
  blockDuration: 900, // Block for 15 minutes
  message: 'Too many authentication attempts, please try again later.'
});

// Validation schemas
const registerSchema = Joi.object({
  username: Joi.string().min(3).max(30).required(),
  email: Joi.string().email().required(),
  password: Joi.string().min(6).required()
});

const loginSchema = Joi.object({
  email: Joi.string().email().required(),
  password: Joi.string().required()
});

// Register route
router.post('/register', async (req, res) => {
  try {
    // Rate limiting check
    const resLimiter = await authLimiter.consume(req.ip);
    if (!resLimiter.remainingPoints) {
      return res.status(429).json({ error: 'Too many authentication attempts, please try again later.' });
    }

    const { error } = registerSchema.validate(req.body);
    if (error) {
      return res.status(400).json({ error: error.details[0].message });
    }

    const { username, email, password } = req.body;

    // Check if user already exists
    const existingUser = await Player.findOne({ 
      $or: [{ email }, { username }] 
    });

    if (existingUser) {
      return res.status(400).json({ 
        error: 'User with this email or username already exists' 
      });
    }

    // Hash password
    const salt = await bcrypt.genSalt(10);
    const hashedPassword = await bcrypt.hash(password, salt);

    // Create new player
    const player = new Player({
      userId: `user_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      username,
      email,
      password: hashedPassword,
      createdAt: new Date(),
      lastLogin: new Date()
    });

    await player.save();

    // Create JWT token
    const token = jwt.sign(
      { userId: player.userId, email: player.email },
      process.env.JWT_SECRET || 'fallback_secret',
      { expiresIn: '24h' }
    );

    logger.info(`New user registered: ${email}`);

    res.status(201).json({
      message: 'User registered successfully',
      token,
      user: {
        userId: player.userId,
        username: player.username,
        email: player.email,
        stats: player.stats
      }
    });

  } catch (error) {
    logger.error('Registration error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

// Login route
router.post('/login', async (req, res) => {
  try {
    // Rate limiting check
    const resLimiter = await authLimiter.consume(req.ip);
    if (!resLimiter.remainingPoints) {
      return res.status(429).json({ error: 'Too many authentication attempts, please try again later.' });
    }

    const { error } = loginSchema.validate(req.body);
    if (error) {
      return res.status(400).json({ error: error.details[0].message });
    }

    const { email, password } = req.body;

    // Find user
    const player = await Player.findOne({ email }).select('+password');
    if (!player) {
      return res.status(401).json({ error: 'Invalid credentials' });
    }

    // Check if password exists (for backward compatibility with existing users)
    if (!player.password) {
      logger.error('Player password field is missing for user:', email);
      return res.status(401).json({ 
        error: 'Account migration required. Please re-register your account.',
        requiresMigration: true 
      });
    }

    // Check password
    const isPasswordValid = await bcrypt.compare(password, player.password);
    if (!isPasswordValid) {
      return res.status(401).json({ error: 'Invalid credentials' });
    }

    // Update last login
    player.stats.lastLogin = new Date();
    await player.save();

    // Create JWT token
    const token = jwt.sign(
      { userId: player.userId, email: player.email },
      process.env.JWT_SECRET || 'fallback_secret',
      { expiresIn: '24h' }
    );

    logger.info(`User logged in: ${email}`);

    res.json({
      message: 'Login successful',
      token,
      user: {
        userId: player.userId,
        username: player.username,
        email: player.email,
        stats: player.stats,
        info: player.info
      }
    });

  } catch (error) {
    logger.error('Login error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

// Verify token route
router.get('/verify', async (req, res) => {
  try {
    const token = req.header('Authorization')?.replace('Bearer ', '');
    
    if (!token) {
      return res.status(401).json({ error: 'No token provided' });
    }

    const decoded = jwt.verify(token, process.env.JWT_SECRET || 'fallback_secret');
    
    const player = await Player.findOne({ userId: decoded.userId });
    if (!player) {
      return res.status(401).json({ error: 'Invalid token' });
    }

    res.json({
      valid: true,
      user: {
        userId: player.userId,
        username: player.username,
        email: player.email,
        stats: player.stats,
        info: player.info
      }
    });

  } catch (error) {
    logger.error('Token verification error:', error);
    res.status(401).json({ error: 'Invalid token' });
  }
});

// Logout route
router.post('/logout', async (req, res) => {
  try {
    // In a real implementation, you might want to blacklist the token
    // For now, we'll just return success
    res.json({ message: 'Logout successful' });
  } catch (error) {
    logger.error('Logout error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

module.exports = router;
