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

// Get all users (admin only)
router.get('/', readLimiter, authenticate, requireAdmin, async (req, res) => {
  const ip = req.ip || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
  const userAgent = req.headers['user-agent'];

  db.all(
    `SELECT id, username, email, role, is_active, created_at, updated_at, created_by,
            failed_login_attempts, last_failed_login, locked_until, last_login_at, last_login_ip,
            password_changed_at, password_expires_at
     FROM users
     ORDER BY created_at DESC`,
    [],
    async (err, users) => {
      if (err) {
        logger.error('Error fetching users:', err);
        return res.status(500).json({ error: 'Failed to fetch users' });
      }

      // CWE-778: Log sensitive data access
      await SecurityAuditLogger.logSensitiveDataAccess(req.user.userId, 'user_list', {
        ip,
        userAgent,
        recordCount: users.length,
        scope: 'all',
        accessMethod: 'view'
      });

      res.json(users);
    }
  );
});

// Get single user (admin only)
router.get('/:id', readLimiter, authenticate, requireAdmin, async (req, res) => {
  const ip = req.ip || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
  const userAgent = req.headers['user-agent'];

  db.get(
    `SELECT id, username, email, role, is_active, created_at, updated_at, created_by
     FROM users WHERE id = ?`,
    [req.params.id],
    async (err, user) => {
      if (err) {
        logger.error('Error fetching user:', err);
        return res.status(500).json({ error: 'Failed to fetch user' });
      }
      if (!user) {
        return res.status(404).json({ error: 'User not found' });
      }

      // CWE-778: Log sensitive data access
      await SecurityAuditLogger.logSensitiveDataAccess(req.user.userId, 'user_details', {
        ip,
        userAgent,
        recordCount: 1,
        scope: 'specific',
        accessMethod: 'view',
        filters: { userId: req.params.id }
      });

      res.json(user);
    }
  );
});

// Create user (admin only)
router.post('/',
  modifyLimiter,
  authenticate,
  requireAdmin,
  [
    body('username').trim().isLength({ min: 3, max: 50 }).isAlphanumeric(),
    body('email').isEmail().normalizeEmail(),
    body('password').isLength({ min: 8 }),
    body('role').isIn(['user', 'admin'])
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }

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

    try {
      const hashedPassword = await bcrypt.hash(password, 10);

      const ip = req.ip || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
      const userAgent = req.headers['user-agent'];

      db.run(
        `INSERT INTO users (username, email, password, role, must_change_password, created_by) 
         VALUES (?, ?, ?, ?, ?, ?)`,
        [username, email, hashedPassword, role, 1, req.user.userId],
        async function(err) {
          if (err) {
            if (err.message.includes('UNIQUE')) {
              return res.status(400).json({ error: 'Username or email already exists' });
            }
            logger.error('User creation error:', err);
            return res.status(500).json({ error: 'Failed to create user' });
          }

          const newUserId = this.lastID;

          // CWE-778: Log admin activity
          await SecurityAuditLogger.logAdminActivity(req.user.userId, 'user_created', {
            ip,
            userAgent,
            targetUserId: newUserId,
            targetUsername: username,
            adminUsername: req.user.username || 'admin',
            changes: { username, email, role }
          });

          db.get(
            `SELECT id, username, email, role, is_active, created_at, created_by
             FROM users WHERE id = ?`,
            [newUserId],
            (err, user) => {
              if (err) {
                return res.status(500).json({ error: 'User created but failed to fetch details' });
              }
              res.status(201).json(user);
            }
          );
        }
      );
    } catch (error) {
      logger.error('User creation error:', error);
      res.status(500).json({ error: 'Failed to create user' });
    }
  }
);

// Update user (admin only)
router.patch('/:id',
  modifyLimiter,
  authenticate,
  requireAdmin,
  [
    body('username').optional().trim().isLength({ min: 3, max: 50 }).isAlphanumeric(),
    body('email').optional().isEmail().normalizeEmail(),
    body('role').optional().isIn(['user', 'admin']),
    body('is_active').optional().isBoolean()
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }

    const { id } = req.params;
    const updates = [];
    const values = [];

    // Build dynamic update query
    if (req.body.username !== undefined) {
      updates.push('username = ?');
      values.push(req.body.username);
    }
    if (req.body.email !== undefined) {
      updates.push('email = ?');
      values.push(req.body.email);
    }
    // Check if role or is_active is being changed (for audit logging)
    const isRoleChange = req.body.role !== undefined;
    const isStatusChange = req.body.is_active !== undefined;

    if (req.body.role !== undefined) {
      updates.push('role = ?');
      values.push(req.body.role);
    }
    if (req.body.is_active !== undefined) {
      updates.push('is_active = ?');
      values.push(req.body.is_active ? 1 : 0);
    }

    if (updates.length === 0) {
      return res.status(400).json({ error: 'No valid fields to update' });
    }

    // Get current user data for audit logging
    db.get('SELECT role, is_active, username FROM users WHERE id = ?', [id], async (err, existingUser) => {
      if (err || !existingUser) {
        return res.status(404).json({ error: 'User not found' });
      }

      updates.push('updated_at = CURRENT_TIMESTAMP');
      values.push(id);

      db.run(
        `UPDATE users SET ${updates.join(', ')} WHERE id = ?`,
        values,
        async function(err) {
          if (err) {
            if (err.message.includes('UNIQUE')) {
              return res.status(400).json({ error: 'Username or email already exists' });
            }
            logger.error('User update error:', err);
            return res.status(500).json({ error: 'Failed to update user' });
          }

          if (this.changes === 0) {
            return res.status(404).json({ error: 'User not found' });
          }

          const ip = req.ip || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
          const userAgent = req.headers['user-agent'];

          // CWE-778: Log privilege changes if role changed
          if (isRoleChange && req.body.role !== existingUser.role) {
            await SecurityAuditLogger.logPrivilegeChange(parseInt(id), 'role_change', {
              ip,
              userAgent,
              previousRole: existingUser.role,
              newRole: req.body.role,
              changedBy: req.user.userId,
              changedByUsername: req.user.username || 'system',
              targetUsername: existingUser.username
            });
          }

          // CWE-778: Log account status changes
          if (isStatusChange && req.body.is_active !== (existingUser.is_active === 1)) {
            const newStatus = req.body.is_active ? 'active' : 'inactive';
            await SecurityAuditLogger.logAccountStatusChange(parseInt(id), newStatus, {
              ip,
              userAgent,
              previousStatus: existingUser.is_active === 1 ? 'active' : 'inactive',
              changedBy: req.user.userId,
              changedByUsername: req.user.username || 'system',
              targetUsername: existingUser.username,
              reason: 'admin_action'
            });
          }

          db.get(
            `SELECT id, username, email, role, is_active, created_at, updated_at, created_by
             FROM users WHERE id = ?`,
            [id],
            (err, user) => {
              if (err) {
                return res.status(500).json({ error: 'User updated but failed to fetch details' });
              }
              res.json(user);
            }
          );
        }
      );
    });
  }
);

// Reset user password (admin only)
router.post('/:id/reset-password',
  modifyLimiter,
  authenticate,
  requireAdmin,
  [
    body('newPassword').isLength({ min: 8 })
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }

    const { id } = req.params;
    const { newPassword } = req.body;

    try {
      const ip = req.ip || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
      const userAgent = req.headers['user-agent'];

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

        const hashedPassword = await bcrypt.hash(newPassword, 10);

        db.run(
          'UPDATE users SET password = ?, must_change_password = 1, updated_at = CURRENT_TIMESTAMP WHERE id = ?',
          [hashedPassword, id],
          async function(err) {
            if (err) {
              logger.error('Password reset error:', err);
              return res.status(500).json({ error: 'Failed to reset password' });
            }

            if (this.changes === 0) {
              return res.status(404).json({ error: 'User not found' });
            }

            // CWE-778: Log admin activity
            await SecurityAuditLogger.logAdminActivity(req.user.userId, 'password_reset', {
              ip,
              userAgent,
              targetUserId: id,
              targetUsername: user.username,
              adminUsername: req.user.username || 'admin',
              reason: 'admin_initiated'
            });

            res.json({ message: 'Password reset successfully. User must change password on next login.' });
          }
        );
      });
    } catch (error) {
      logger.error('Password reset error:', error);
      res.status(500).json({ error: 'Failed to reset password' });
    }
  }
);

// Unlock account (admin only)
router.post('/:id/unlock', modifyLimiter, authenticate, requireAdmin, async (req, res) => {
  const { id } = req.params;
  const ip = req.ip || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
  const userAgent = req.headers['user-agent'];

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

      db.run(
        'UPDATE users SET locked_until = NULL, failed_login_attempts = 0 WHERE id = ?',
        [id],
        async function(err) {
          if (err) {
            logger.error('Account unlock error:', err);
            return res.status(500).json({ error: 'Failed to unlock account' });
          }

          if (this.changes === 0) {
            return res.status(404).json({ error: 'User not found' });
          }

          // CWE-778: Log admin activity
          await SecurityAuditLogger.logAdminActivity(req.user.userId, 'account_unlocked', {
            ip,
            userAgent,
            targetUserId: id,
            targetUsername: user.username,
            adminUsername: req.user.username || 'admin',
            changes: { locked_until: user.locked_until, failed_login_attempts: 0 },
            reason: 'admin_unlock'
          });

          logger.info(`Admin ${req.user.userId} unlocked account ${id}`);
          res.json({ message: 'Account unlocked successfully' });
        }
      );
    });
  } catch (error) {
    logger.error('Account unlock error:', error);
    res.status(500).json({ error: 'Failed to unlock account' });
  }
});

// Delete user (admin only)
router.delete('/:id', modifyLimiter, authenticate, requireAdmin, async (req, res) => {
  const { id } = req.params;
  const ip = req.ip || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
  const userAgent = req.headers['user-agent'];

  // Prevent deleting yourself
  if (parseInt(id) === req.user.userId) {
    return res.status(400).json({ error: 'Cannot delete your own account' });
  }

  // Check if this is the last admin
  db.get(
    "SELECT COUNT(*) as count FROM users WHERE role = 'admin' AND is_active = 1",
    [],
    (err, result) => {
      if (err) {
        logger.error('Error checking admin count:', err);
        return res.status(500).json({ error: 'Failed to delete user' });
      }

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

        if (user.role === 'admin' && result.count <= 1) {
          return res.status(400).json({ error: 'Cannot delete the last admin account' });
        }

        db.run('DELETE FROM users WHERE id = ?', [id], async function(err) {
          if (err) {
            logger.error('User deletion error:', err);
            return res.status(500).json({ error: 'Failed to delete user' });
          }

          if (this.changes === 0) {
            return res.status(404).json({ error: 'User not found' });
          }

          // CWE-778: Log admin activity - user deletion
          await SecurityAuditLogger.logAdminActivity(req.user.userId, 'user_deleted', {
            ip,
            userAgent,
            targetUserId: id,
            targetUsername: user.username,
            adminUsername: req.user.username || 'admin',
            changes: { deleted: { username: user.username, email: user.email, role: user.role } },
            reason: 'admin_deletion'
          });

          res.json({ message: 'User deleted successfully' });
        });
      });
    }
  );
});

module.exports = router;
