const UserAddress = require('../models/UserAddress');
const Address = require('../models/Address');
const { validationResult } = require('express-validator');
const mongoose = require('mongoose');

// @desc    Get all addresses for a user
// @route   GET /api/users/:userId/addresses
// @access  Private
exports.getUserAddresses = async (req, res) => {
  try {
    // Check if the request is for the user's own addresses or if admin is making the request
    if (req.user.role !== 'admin' && req.user.id !== req.params.userId) {
      return res.status(403).json({ 
        success: false, 
        msg: 'Not authorized to view these addresses' 
      });
    }
    
    const userAddresses = await UserAddress.getByUser(req.params.userId, true);
    
    res.json({ 
      success: true, 
      data: userAddresses,
      count: userAddresses.length
    });
  } catch (error) {
    console.error('Error fetching user addresses:', error);
    res.status(500).json({ success: false, msg: 'Server error' });
  }
};

// @desc    Add a new address for a user
// @route   POST /api/users/:userId/addresses
// @access  Private
exports.addUserAddress = async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ success: false, errors: errors.array() });
  }

  // Check if the user is authorized to add an address for this user
  if (req.user.role !== 'admin' && req.user.id !== req.params.userId) {
    return res.status(403).json({ 
      success: false, 
      msg: 'Not authorized to add an address for this user' 
    });
  }

  try {
    const { 
      name,
      contactNumber,
      country = 'India', 
      state, 
      city, 
      postcode, 
      address, 
      landmark,
      latitude, 
      longitude, 
      type = 'home',
      is_default = false 
    } = req.body;
    
    try {
      // Prepare address data
      const addressData = {
        user: new mongoose.Types.ObjectId(req.params.userId),
        name,
        contactNumber,
        country,
        state,
        city,
        postcode,
        address,
        landmark,
        type,
        isDefault: is_default
      };

      // Only add location if both latitude and longitude are provided and valid numbers
      if (latitude !== undefined && longitude !== undefined) {
        const lat = parseFloat(latitude);
        const lng = parseFloat(longitude);
        
        if (!isNaN(lat) && !isNaN(lng)) {
          addressData.location = {
            type: 'Point',
            coordinates: [lng, lat] // GeoJSON uses [longitude, latitude] order
          };
        }
      }

      // Create the address document
      const newAddress = await Address.create(addressData);

      // If this is set as default, update other addresses
      if (is_default) {
        await UserAddress.model.updateMany(
          { user: req.params.userId },
          { $set: { isDefault: false } }
        );
      }

      // Create the user address mapping
      const userAddress = await UserAddress.create({
        user: new mongoose.Types.ObjectId(req.params.userId),
        address: newAddress._id,
        isDefault: is_default
      });

      // Get the populated address
      const populatedAddress = await UserAddress.model
        .findById(userAddress._id)
        .populate('address', '-__v -createdAt -updatedAt')
        .select('-__v -createdAt -updatedAt')
        .lean();

      res.status(201).json({ 
        success: true, 
        data: {
          ...populatedAddress.address,
          id: populatedAddress._id,
          is_default: populatedAddress.isDefault,
          address_id: populatedAddress.address._id
        },
        msg: 'Address added successfully' 
      });
    } catch (error) {
      console.error('Error adding user address:', error);
      res.status(500).json({ 
        success: false, 
        msg: 'Error adding address', 
        error: error.message 
      });
    }
  } catch (error) {
    console.error('Unexpected error:', error);
    res.status(500).json({ 
      success: false, 
      msg: 'Unexpected error occurred',
      error: error.message 
    });
  }
};

// @desc    Update a user's address
// @route   PUT /api/users/:userId/addresses/:addressId
// @access  Private
exports.updateUserAddress = async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ success: false, errors: errors.array() });
  }

  try {
    const { userId, addressId } = req.params;
    const { 
      country, 
      state, 
      city, 
      postcode, 
      address, 
      latitude, 
      longitude, 
      is_default 
    } = req.body;
    
    // Check if the user is authorized to update this address
    if (req.user.role !== 'admin' && req.user.id !== userId) {
      return res.status(403).json({ 
        success: false, 
        msg: 'Not authorized to update this address' 
      });
    }
    
    // Get the user address to verify ownership
    const userAddresses = await UserAddress.getByUser(userId);
    const userAddress = userAddresses.find(ua => ua.id == addressId);
    
    if (!userAddress) {
      return res.status(404).json({ 
        success: false, 
        msg: 'Address not found for this user' 
      });
    }
    
    // Update the address
    await Address.update(userAddress.address_id, {
      country,
      state,
      city,
      postcode,
      address,
      latitude,
      longitude
    });
    
    // If setting as default, update other addresses
    if (is_default) {
      await UserAddress.setDefault(userId, userAddress.address_id);
    }
    
    // Get the updated address
    const updatedAddresses = await UserAddress.getByUser(userId, true);
    const updatedAddress = updatedAddresses.find(ua => ua.id == addressId);
    
    res.json({ 
      success: true, 
      data: updatedAddress,
      msg: 'Address updated successfully' 
    });
  } catch (error) {
    console.error('Error updating user address:', error);
    res.status(500).json({ success: false, msg: 'Error updating address' });
  }
};

// @desc    Set default address for a user
// @route   PUT /api/users/:userId/addresses/:addressId/set-default
// @access  Private
exports.setDefaultAddress = async (req, res) => {
  try {
    const { userId, addressId } = req.params;
    
    // Check if the user is authorized to update this address
    if (req.user.role !== 'admin' && req.user.id !== userId) {
      return res.status(403).json({ 
        success: false, 
        msg: 'Not authorized to update this address' 
      });
    }
    
    // Get the user address to verify ownership
    const userAddresses = await UserAddress.getByUser(userId);
    const userAddress = userAddresses.find(ua => ua.id == addressId);
    
    if (!userAddress) {
      return res.status(404).json({ 
        success: false, 
        msg: 'Address not found for this user' 
      });
    }
    
    // Set as default
    await UserAddress.setDefault(userId, userAddress.address_id);
    
    res.json({ 
      success: true, 
      msg: 'Default address updated successfully' 
    });
  } catch (error) {
    console.error('Error setting default address:', error);
    res.status(500).json({ success: false, msg: 'Error setting default address' });
  }
};

// @desc    Delete a user's address
// @route   DELETE /api/users/:userId/addresses/:addressId
// @access  Private
exports.deleteUserAddress = async (req, res) => {
  try {
    const { userId, addressId } = req.params;
    
    // Check if the user is authorized to delete this address
    if (req.user.role !== 'admin' && req.user.id !== userId) {
      return res.status(403).json({ 
        success: false, 
        msg: 'Not authorized to delete this address' 
      });
    }
    
    // Get the user address to verify ownership
    const userAddresses = await UserAddress.getByUser(userId);
    const userAddress = userAddresses.find(ua => ua.id == addressId);
    
    if (!userAddress) {
      return res.status(404).json({ 
        success: false, 
        msg: 'Address not found for this user' 
      });
    }
    
    // Don't allow deletion if it's the only address
    if (userAddresses.length === 1) {
      return res.status(400).json({ 
        success: false, 
        msg: 'Cannot delete the only address. Please add another address first.' 
      });
    }
    
    // Delete the user address link
    await UserAddress.deleteUserAddress(userId, userAddress.address_id);
    
    // If this was the default address, set another one as default
    if (userAddress.is_default) {
      const remainingAddresses = userAddresses.filter(ua => ua.id != addressId);
      if (remainingAddresses.length > 0) {
        await UserAddress.setDefault(userId, remainingAddresses[0].address_id);
      }
    }
    
    res.json({ 
      success: true, 
      msg: 'Address deleted successfully' 
    });
  } catch (error) {
    console.error('Error deleting user address:', error);
    res.status(500).json({ success: false, msg: 'Error deleting address' });
  }
};

// @desc    Get default address for a user
// @route   GET /api/users/:userId/addresses/default
// @access  Private
exports.getDefaultAddress = async (req, res) => {
  try {
    const { userId } = req.params;
    
    // Check if the user is authorized
    if (req.user.role !== 'admin' && req.user.id !== userId) {
      return res.status(403).json({ 
        success: false, 
        msg: 'Not authorized to view this address' 
      });
    }
    
    const defaultAddress = await UserAddress.getDefaultAddress(userId);
    
    if (!defaultAddress) {
      return res.status(404).json({ 
        success: false, 
        msg: 'No default address found' 
      });
    }
    
    res.json({ 
      success: true, 
      data: defaultAddress 
    });
  } catch (error) {
    console.error('Error fetching default address:', error);
    res.status(500).json({ success: false, msg: 'Server error' });
  }
};
