const User = require('../models/User');
const DeliveryBoy = require('../models/DeliveryBoy');
const Store = require('../models/Store');
const { validationResult } = require('express-validator');

// @desc    Register a new user
// @route   POST /api/users/register
// @access  Public
exports.register = async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ success: false, errors: errors.array() });
  }

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

  try {
    // Check if user exists
    let user = await User.findByEmail(email);
    if (user) {
      return res.status(400).json({ 
        success: false, 
        errors: [{ msg: 'User already exists' }] 
      });
    }

    // Create user - password will be hashed by the pre-save hook
    const newUser = await User.create({
      name,
      email,
      password, // Will be hashed by pre-save hook
      phone,
      role: role || 'customer',
      status: true
    });

    // Generate JWT token using the instance method
    const token = newUser.getSignedJwtToken();

    // Return token and user info (without sensitive data)
    const userObj = newUser.toObject();
    delete userObj.password;
    
    res.status(201).json({ 
      success: true, 
      token,
      user: userObj
    });
  } catch (error) {
    console.error('Error in user registration:', error);
    res.status(500).json({ 
      success: false, 
      errors: [{ msg: 'Server error during registration' }] 
    });
  }
};

// @desc    Authenticate user & get token
// @route   POST /api/users/login
// @access  Public
exports.login = async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ success: false, errors: errors.array() });
  }

  const { email, password } = req.body;

  try {
    // Check for user
    const user = await User.findByEmail(email).select('+password');
    if (!user) {
      return res.status(400).json({ 
        success: false, 
        errors: [{ msg: 'Invalid credentials' }] 
      });
    }

    // Check if user is active
    if (!user.status) {
      return res.status(400).json({ 
        success: false, 
        errors: [{ msg: 'Account is deactivated' }] 
      });
    }

    // Check password using instance method
    const isMatch = await user.matchPassword(password);
    if (!isMatch) {
      return res.status(400).json({ 
        success: false, 
        errors: [{ msg: 'Invalid credentials' }] 
      });
    }

    // Generate JWT token using instance method
    const token = user.getSignedJwtToken();

    // Define role-based redirect paths (must match the paths in auth.js)
    const roleRedirects = {
      superadmin: '/admin/dashboard',
      store_manager: '/store/dashboard',
      delivery_boy: '/delivery/dashboard',
      customer: '/'
    };

    // Get user details without sensitive data
    const userObj = user.toObject();
    delete userObj.password;

    // Add role and redirect path to the response
    res.json({
      success: true,
      token,
      user: {
        ...userObj,
        role: user.role,
        redirectTo: roleRedirects[user.role] || '/'
      },
      redirectTo: roleRedirects[user.role] || '/' // For backward compatibility
    });
  } catch (error) {
    console.error('Error in user login:', error);
    res.status(500).json({ 
      success: false, 
      errors: [{ msg: 'Server error during login' }] 
    });
  }
};

// @desc    Get user profile
// @route   GET /api/users/me
// @access  Private
exports.getProfile = async (req, res) => {
  try {
    const user = await User.findById(req.user.id).select('-password');
    if (!user) {
      return res.status(404).json({ 
        success: false, 
        errors: [{ msg: 'User not found' }] 
      });
    }
    res.json({ success: true, user });
  } catch (error) {
    console.error('Error getting user profile:', error);
    res.status(500).json({ 
      success: false, 
      errors: [{ msg: 'Server error' }] 
    });
  }
};

// @desc    Update user profile
// @route   PUT /api/users/me
// @access  Private
exports.updateProfile = async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ success: false, errors: errors.array() });
  }
  
  const { name, email, phone } = req.body;
  const updateData = {};
  
  // Only include fields that are provided in the request
  if (name) updateData.name = name;
  if (email) updateData.email = email;
  if (phone) updateData.phone = phone;

  try {
    // Check if email is being updated and already exists
    if (email) {
      const existingUser = await User.findOne({ email });
      if (existingUser && existingUser._id.toString() !== req.user.id) {
        return res.status(400).json({ 
          success: false, 
          errors: [{ msg: 'Email already in use' }] 
        });
      }
    }

    const user = await User.findByIdAndUpdate(
      req.user.id,
      updateData,
      { new: true, runValidators: true }
    ).select('-password');

    if (!user) {
      return res.status(404).json({ 
        success: false, 
        errors: [{ msg: 'User not found' }] 
      });
    }

    res.json({ 
      success: true, 
      msg: 'Profile updated successfully',
      user 
    });
  } catch (error) {
    console.error('Error updating profile:', error);
    res.status(500).json({ 
      success: false, 
      errors: [{ msg: 'Server error' }] 
    });
  }
};

// @desc    Update user's password
// @route   PUT /api/users/me/password
// @access  Private
exports.updatePassword = async (req, res) => {
  const { currentPassword, newPassword } = req.body;

  try {
    const user = await User.findById(req.user.id).select('+password');
    if (!user) {
      return res.status(404).json({ 
        success: false, 
        errors: [{ msg: 'User not found' }] 
      });
    }

    // Check current password
    const isMatch = await user.matchPassword(currentPassword);
    if (!isMatch) {
      return res.status(400).json({ 
        success: false, 
        errors: [{ msg: 'Current password is incorrect' }] 
      });
    }

    // Update password
    user.password = newPassword;
    await user.save();

    res.json({ 
      success: true, 
      msg: 'Password updated successfully' 
    });
  } catch (error) {
    console.error('Error updating password:', error);
    res.status(500).json({ 
      success: false, 
      errors: [{ msg: 'Server error' }] 
    });
  }
};

// @desc    Get all users (Admin only)
// @route   GET /api/users
// @access  Private/Admin
exports.getUsers = async (req, res) => {
  try {
    // Exclude deleted users and sensitive data
    const users = await User.find({ deletedAt: { $exists: false } })
      .select('-password -resetPasswordToken -resetPasswordExpire')
      .sort({ createdAt: -1 });
      
    res.json({ 
      success: true, 
      count: users.length, 
      data: users 
    });
  } catch (error) {
    console.error('Error getting users:', error);
    res.status(500).json({ 
      success: false, 
      errors: [{ msg: 'Server error while fetching users' }] 
    });
  }
};

// @desc    Update user (Admin only)
// @route   PUT /api/users/:id
// @access  Private/Admin
exports.updateUser = async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ success: false, errors: errors.array() });
  }
  
  const { name, email, phone, role, status } = req.body;
  const updateData = {};
  
  // Only include fields that are provided in the request
  if (name) updateData.name = name;
  if (email) updateData.email = email;
  if (phone) updateData.phone = phone;
  if (role) updateData.role = role;
  if (status !== undefined) updateData.status = status;
  
  try {
    const user = await User.findByIdAndUpdate(
      req.params.id,
      { $set: updateData },
      { new: true, runValidators: true }
    ).select('-password -resetPasswordToken -resetPasswordExpire');
    
    if (!user) {
      return res.status(404).json({ 
        success: false, 
        errors: [{ msg: 'User not found' }] 
      });
    }
    
    res.json({ 
      success: true, 
      data: user 
    });
  } catch (error) {
    console.error('Error updating user:', error);
    
    // Handle duplicate key errors
    if (error.code === 11000) {
      return res.status(400).json({
        success: false,
        errors: [{ msg: 'Email or phone number already in use' }]
      });
    }
    
    res.status(500).json({ 
      success: false, 
      errors: [{ msg: 'Server error while updating user' }] 
    });
  }
};

// @desc    Delete user (Admin only)
// @route   DELETE /api/users/:id
// @access  Private/Admin
exports.deleteUser = async (req, res) => {
  const session = await mongoose.startSession();
  session.startTransaction();
  
  try {
    // Find the user first to get their role
    const user = await User.findById(req.params.id).session(session);
    
    if (!user) {
      await session.abortTransaction();
      session.endSession();
      return res.status(404).json({ 
        success: false, 
        errors: [{ msg: 'User not found' }] 
      });
    }

    // Delete related records based on user role
    if (user.role === 'delivery_boy') {
      // Delete from delivery boys collection
      await DeliveryBoy.findOneAndDelete({ user: user._id }).session(session);
    } else if (user.role === 'store_manager') {
      // Delete from stores collection
      await Store.findOneAndDelete({ email: user.email }).session(session);
    }
    
    // Perform a soft delete of the user
    await User.findByIdAndUpdate(
      req.params.id,
      { $set: { deletedAt: new Date() } },
      { new: true, session }
    );
    
    // Commit the transaction
    await session.commitTransaction();
    session.endSession();
    
    res.json({ 
      success: true, 
      msg: 'User and related records deleted successfully' 
    });
    
  } catch (error) {
    // If anything fails, rollback the transaction
    await session.abortTransaction();
    session.endSession();
    
    console.error('Error deleting user:', error);
    
    // Handle specific error cases
    if (error.name === 'CastError') {
      return res.status(400).json({
        success: false,
        errors: [{ msg: 'Invalid user ID format' }]
      });
    }
    
    res.status(500).json({ 
      success: false, 
      errors: [{ 
        msg: error.message || 'Server error while deleting user and related records'
      }] 
    });
  }
};
