const mongoose = require('mongoose');
const PickerPacker = require('../models/PickerPacker');
const Store = require('../models/Store');
const User = require('../models/User');
const fs = require('fs');
const path = require('path');
const bcrypt = require('bcryptjs');
const { checkPermission } = require('../middleware/permission');

// Get all picker packers with pagination and search
exports.getPickerPackers = async (req, res) => {
  try {
    // Parse query parameters with defaults
    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 10;
    const { search, status, shift, store, populate = 'store' } = req.query;

    // Build filter object
    const filter = {};
    
    // Add status filter if provided
    if (status && status !== 'all') {
      filter.status = status;
    }

    // Add store filter
    if (store) {
      filter.store = store;
    } else if (req.user?.role === 'store_manager' && req.user.store) {
      // For store managers, filter by their store
      filter.store = req.user.store._id || req.user.store;
    } else if (req.user?.role === 'admin') {
      // Admins can see all picker packers, no store filter needed
    } else {
      // For other roles or unauthenticated users, return empty
      return res.status(200).json({
        success: true,
        data: [],
        total: 0,
        page,
        limit,
        totalPages: 1,
        msg: 'No picker packers found',
        pagination: {
          total: 0,
          page: 1,
          limit,
          pages: 1
        }
      });
    }

    // Add shift filter if provided
    if (shift && shift !== 'all') {
      filter.shift = shift;
    }

    // Add search filter if provided
    if (search) {
      filter.$or = [
        { name: { $regex: search, $options: 'i' } },
        { email: { $regex: search, $options: 'i' } },
        { employee_id: search }
      ];
    }

    // Build query options
    const options = {
      page,
      limit,
      filter,
      populate
    };

    // Execute query with proper population
    const result = await PickerPacker.findAllActive({
      ...options,
      populate: 'store user',
      lean: true
    });

    // Log the query and result for debugging
    console.log('PickerPacker query filter:', filter);
    console.log('PickerPacker query result:', result);

    // Handle the response structure from findAllActive
    const items = result.pickerPackers || [];
    const pagination = result.pagination || {
      total: items.length,
      page: parseInt(page),
      limit: parseInt(limit),
      pages: Math.ceil((result.pagination?.total || items.length) / limit)
    };
    
    const { total, page: currentPage, limit: itemsPerPage, pages: totalPages } = pagination;

    // Prepare response
    const response = {
      success: true,
      data: items,
      total: total,
      page: currentPage,
      limit: itemsPerPage,
      totalPages: totalPages,
      msg: items.length ? 'Picker packers retrieved successfully' : 'No picker packers found',
      pagination: {
        total: total,
        page: currentPage,
        limit: itemsPerPage,
        pages: totalPages
      }
    };

    res.status(200).json(response);
  } catch (error) {
    console.error('Error in getPickerPackers:', error);
    res.status(500).json({
      success: false,
      msg: 'Server error while fetching picker packers',
      error: process.env.NODE_ENV === 'development' ? error.message : undefined
    });
  }
};

// Get picker packer by user ID
exports.getPickerPackerByUserId = async (req, res) => {
  try {
    const { userId } = req.params;
    
    // Find picker packer by user ID
    const pickerPacker = await PickerPacker.findOne({ user: userId })
      .populate('store', 'name address city state')
      .select('-__v');

    if (!pickerPacker) {
      return res.status(404).json({
        success: false,
        message: 'Picker/Packer not found for the given user ID'
      });
    }

    res.status(200).json({
      success: true,
      data: pickerPacker
    });
  } catch (error) {
    console.error('Error getting picker/packer by user ID:', error);
    res.status(500).json({
      success: false,
      message: 'Error retrieving picker/packer',
      error: error.message
    });
  }
};

// Get picker packer by ID
exports.getPickerPackerById = async (req, res) => {
    try {
        // Check permission
        const hasPermission = await checkPermission(req.user.id, 'picker_packer_view');
        if (!hasPermission) {
            return res.status(403).json({ error: 'You do not have permission to view picker packers' });
        }

        const pickerPacker = await PickerPacker.findById(req.params.id);
        
        if (!pickerPacker) {
            return res.status(404).json({ error: 'Picker packer not found' });
        }

        // Check if the picker packer belongs to the user's store
        if (pickerPacker.store.toString() !== req.user.store.toString()) {
            return res.status(403).json({ error: 'You do not have permission to view this picker packer' });
        }

        res.status(200).json(pickerPacker);
    } catch (error) {
        console.error('Error fetching picker packer:', error);
        res.status(500).json({ error: 'Failed to fetch picker packer' });
    }
};

// Create a new picker packer
exports.createPickerPacker = async (req, res) => {
  // Don't use transactions for development
  const useTransactions = false;
  const session = useTransactions ? await mongoose.startSession() : null;
  
  if (useTransactions && session) {
    await session.startTransaction();
  }
  
  try {
    const { 
      name, 
      email, 
      password, 
      phone, 
      employee_id, 
      shift = 'morning',
      status = 'active',
      joining_date = new Date()
    } = req.body;
    
    // Validation
    if (!name || !email || !password) {
      if (session) {
        await session.abortTransaction();
        session.endSession();
      }
      return res.status(400).json({
        success: false,
        msg: 'Name, email and password are required'
      });
    }

    // Normalize email and trim whitespace
    const normalizedEmail = email.toLowerCase().trim();
    console.log('Processing email:', normalizedEmail);
    
    // Basic email format validation
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalizedEmail)) {
      const errorMsg = 'Please provide a valid email address';
      console.log('Email format validation failed:', { email, normalizedEmail });
      if (session) {
        await session.abortTransaction();
        session.endSession();
      }
      return res.status(400).json({
        success: false,
        msg: errorMsg
      });
    }

    // Check if email already exists in User or PickerPacker collection
    try {
      console.log('Checking for existing email in database...');
      
      // First, try exact match
      const [exactUserMatch, exactPickerPackerMatch] = await Promise.all([
        User.findOne({ email: normalizedEmail }),
        PickerPacker.findOne({ email: normalizedEmail })
      ]);
      
      console.log('Exact match results:', { 
        user: exactUserMatch ? 'found' : 'not found',
        pickerPacker: exactPickerPackerMatch ? 'found' : 'not found'
      });
      
      // If no exact match, try case-insensitive search
      if (!exactUserMatch && !exactPickerPackerMatch) {
        const [caseInsensitiveUser, caseInsensitivePickerPacker] = await Promise.all([
          User.findOne({ email: { $regex: new RegExp(`^${normalizedEmail}$`, 'i') } }),
          PickerPacker.findOne({ email: { $regex: new RegExp(`^${normalizedEmail}$`, 'i') } })
        ]);
        
        console.log('Case-insensitive match results:', {
          user: caseInsensitiveUser ? 'found' : 'not found',
          pickerPacker: caseInsensitivePickerPacker ? 'found' : 'not found'
        });
        
        if (caseInsensitiveUser) {
          console.log('Found case-insensitive match in User collection:', {
            id: caseInsensitiveUser._id,
            email: caseInsensitiveUser.email
          });
        }
        
        if (caseInsensitivePickerPacker) {
          console.log('Found case-insensitive match in PickerPacker collection:', {
            id: caseInsensitivePickerPacker._id,
            email: caseInsensitivePickerPacker.email
          });
        }
        
        if (caseInsensitiveUser || caseInsensitivePickerPacker) {
          if (session) {
            await session.abortTransaction();
            session.endSession();
          }
          return res.status(409).json({
            success: false,
            msg: 'This email address is already in use (case-insensitive match found).',
            details: {
              existingEmail: caseInsensitiveUser?.email || caseInsensitivePickerPacker?.email,
              collection: caseInsensitiveUser ? 'User' : 'PickerPacker'
            }
          });
        }
      } else if (exactUserMatch || exactPickerPackerMatch) {
        const existingEmail = exactUserMatch?.email || exactPickerPackerMatch?.email;
        console.log('Exact email match found:', existingEmail);
        if (session) {
          await session.abortTransaction();
          session.endSession();
        }
        return res.status(409).json({
          success: false,
          msg: 'This email address is already in use.',
          details: {
            existingEmail,
            collection: exactUserMatch ? 'User' : 'PickerPacker'
          }
        });
      }
    } catch (error) {
      console.error('Error checking for existing email:', error);
      if (session) {
        await session.abortTransaction();
        session.endSession();
      }
      return res.status(500).json({
        success: false,
        msg: 'Error validating email. Please try again.'
      });
    }

    // Handle uploaded image
    let imagePath = null;
    if (req.file) {
      // The image is already saved in the picker_packers directory by multer
      // Just need to store the relative path
      imagePath = `/uploads/picker_packers/${req.file.filename}`;
      console.log('Image uploaded to:', path.join(process.cwd(), 'uploads', 'picker_packers', req.file.filename));
    }

    // Set store ID (from authenticated user if store manager or admin)
    let storeId;
    
    // If user is store manager or admin, try to get their store
    if (req.user && (req.user.role === 'store_manager' || req.user.role === 'admin')) {
      try {
        // Find the store associated with this user
        const store = await Store.findOne({ user: req.user.id });
        
        if (store) {
          storeId = store._id;
          console.log(`Found store ${storeId} for user ${req.user.id}`);
        } else if (req.body.store) {
          // Fallback to provided store ID if user doesn't have a store
          storeId = req.body.store;
        } else {
          throw new Error('No store associated with this user and no store ID provided');
        }
      } catch (storeError) {
        console.error('Error fetching store for user:', storeError);
        throw new Error('Error determining store association');
      }
    } else if (req.body.store) {
      // For other roles, use the provided store ID if allowed
      storeId = req.body.store;
    } else {
      if (session) {
        await session.abortTransaction();
        session.endSession();
      }
      return res.status(400).json({
        success: false,
        msg: 'Store ID is required and could not be determined from your account'
      });
    }
    
    // Validate store ID format
    if (!mongoose.Types.ObjectId.isValid(storeId)) {
      if (session) {
        await session.abortTransaction();
        session.endSession();
      }
      return res.status(400).json({
        success: false,
        msg: 'Invalid store ID format. Please provide a valid store ID.'
      });
    }
    
    // Convert storeId to ObjectId
    try {
      storeId = new mongoose.Types.ObjectId(storeId);
    } catch (error) {
      if (session) {
        await session.abortTransaction();
        session.endSession();
      }
      return res.status(400).json({
        success: false,
        msg: 'Invalid store ID format. Please provide a valid store ID.'
      });
    }

    // Generate a single ID for both user and picker packer
    const userId = new mongoose.Types.ObjectId();
    
    // Hash password
    const salt = await bcrypt.genSalt(10);
    const hashedPassword = await bcrypt.hash(password, salt);

    // 1. Create user with picker_packer role using the same ID
    const userData = {
      _id: userId,
      name,
      email: normalizedEmail,
      password: hashedPassword,
      phone,
      role: 'picker_packer',
      status: status === 'active',
      pickerPacker: userId
    };

    console.log('Creating user with data:', {
      _id: userId,
      email: normalizedEmail,
      name,
      phone,
      role: 'picker_packer',
      status: status === 'active'
    });

    // 2. Create picker packer with the same ID
    const pickerPackerData = {
      _id: userId,
      user: userId,
      name,
      email: normalizedEmail,
      phone,
      employee_id,
      shift,
      status,
      image: imagePath,
      joining_date,
      store: storeId
    };

    console.log('Creating picker packer with data:', {
      _id: userId,
      email: normalizedEmail,
      name,
      phone,
      employee_id,
      shift,
      store: storeId
    });

    // Use transaction if enabled
    if (useTransactions && session) {
      try {
        // Create both user and picker packer in a transaction
        console.log('Starting transaction for user and picker packer creation');
        const [user, pickerPacker] = await Promise.all([
          User.create([userData], { session }),
          PickerPacker.create([pickerPackerData], { session })
        ]);
        
        await session.commitTransaction();
        session.endSession();
        
        console.log('Successfully created user and picker packer in transaction');
        return res.status(201).json({
          success: true,
          data: {
            ...pickerPacker[0].toObject(),
            user: user[0]._id
          },
          msg: 'Picker packer created successfully'
        });
      } catch (transactionError) {
        console.error('Transaction error:', transactionError);
        await session.abortTransaction();
        session.endSession();
        throw transactionError; // Re-throw to be caught by the outer catch
      }
    } else {
      // Without transactions - create user first, then picker packer
      console.log('Creating user and picker packer without transaction');
      let user;
      try {
        console.log('Creating user...');
        user = await User.create(userData);
        console.log('User created successfully:', { userId: user._id });
        
        console.log('Creating picker packer...');
        const pickerPacker = await PickerPacker.create(pickerPackerData);
        console.log('Picker packer created successfully:', { pickerPackerId: pickerPacker._id });
        
        return res.status(201).json({
          success: true,
          data: {
            ...pickerPacker.toObject(),
            user: user._id
          },
          msg: 'Picker packer created successfully'
        });
        
      } catch (error) {
        console.error('Error in user/picker packer creation:', error);
        
        // Cleanup if user was created but picker packer creation failed
        if (user && user._id) {
          console.log('Cleaning up: deleting user due to error');
          await User.findByIdAndDelete(user._id);
          
          // Also delete the uploaded file if it exists
          if (imagePath) {
            const filePath = path.join(process.cwd(), imagePath);
            try {
              console.log('Deleting uploaded file:', filePath);
              await fs.unlink(filePath);
            } catch (unlinkError) {
              console.error('Error deleting uploaded file:', unlinkError);
            }
          }
        }
        
        // Handle specific error cases
        if (error.code === 11000) {
          console.error('Duplicate key error:', error.keyValue);
          return res.status(409).json({
            success: false,
            msg: `Email '${error.keyValue?.email || normalizedEmail}' already exists in the system`,
            error: process.env.NODE_ENV === 'development' ? error.message : undefined
          });
        }
        
        if (error.name === 'ValidationError') {
          console.error('Validation error:', error.errors);
          return res.status(400).json({
            success: false,
            msg: 'Validation error',
            errors: error.errors,
            error: process.env.NODE_ENV === 'development' ? error.message : undefined
          });
        }
        
        throw error; // Re-throw to be caught by the outer catch
      }
    }
  } catch (error) {
    console.error('Error in createPickerPacker:', error);
    
    // Clean up session if it exists
    if (session) {
      await session.abortTransaction();
      session.endSession();
    }
    
    // Default error response
    return res.status(500).json({
      success: false,
      msg: 'An error occurred while creating picker packer',
      error: process.env.NODE_ENV === 'development' ? error.message : undefined
    });
  }
};

// Update a picker packer
exports.updatePickerPacker = async (req, res) => {
    try {
        const { id } = req.params;
        const {
            name,
            email,
            password,
            phone,
            employeeId,
            shift,
            performanceRating,
            status,
            ordersProcessed
        } = req.body;

        // Find the picker packer with user details populated
        const pickerPacker = await PickerPacker.findById(id).populate('user', 'email');
        
        if (!pickerPacker) {
            return res.status(404).json({ 
                success: false,
                msg: 'Picker packer not found' 
            });
        }

        // Check if the picker packer belongs to the user's store
        const pickerStoreId = pickerPacker.store?._id?.toString() || pickerPacker.store?.toString();
        const userStoreId = req.user.store?._id?.toString() || req.user.store?.toString();
        
        if (req.user.role === 'store_manager' && pickerStoreId !== userStoreId) {
            return res.status(403).json({ 
                success: false,
                msg: 'You do not have permission to update this picker packer' 
            });
        }

        // Check if email is being updated
        if (email && email.toLowerCase() !== pickerPacker.email?.toLowerCase()) {
            const normalizedEmail = email.toLowerCase();
            
            // Check if email exists in User collection (excluding current user)
            const existingUser = await User.findOne({
                email: normalizedEmail,
                _id: { $ne: pickerPacker.user?._id || pickerPacker.user }
            });
            
            if (existingUser) {
                return res.status(409).json({
                    success: false,
                    msg: 'Email already exists in the system'
                });
            }

            // Check if email exists in PickerPacker collection (excluding current picker packer)
            const existingPickerPacker = await PickerPacker.findOne({
                email: normalizedEmail,
                _id: { $ne: id }
            });

            if (existingPickerPacker) {
                return res.status(409).json({
                    success: false,
                    msg: 'Email already exists'
                });
            }
            
            // Update the email in both User and PickerPacker collections
            if (pickerPacker.user) {
                await User.findByIdAndUpdate(pickerPacker.user._id || pickerPacker.user, { 
                    email: normalizedEmail 
                });
            }
            
            // Update the email in the picker packer
            pickerPacker.email = normalizedEmail;
        }

        // Update other fields
        const updateData = {
            name: name || pickerPacker.name,
            phone: phone || pickerPacker.phone,
            employeeId: employeeId || pickerPacker.employeeId,
            shift: shift || pickerPacker.shift,
            status: status || pickerPacker.status
        };

        // Only update performanceRating and ordersProcessed if provided
        if (performanceRating !== undefined) updateData.performanceRating = performanceRating;
        if (ordersProcessed !== undefined) updateData.ordersProcessed = ordersProcessed;

        // Update password if provided
        if (password) {
            const salt = await bcrypt.genSalt(10);
            updateData.password = await bcrypt.hash(password, 10);
            
            // Also update in User collection if exists
            if (pickerPacker.user) {
                await User.findByIdAndUpdate(pickerPacker.user._id || pickerPacker.user, { 
                    password: updateData.password
                });
            }
        }

        // Handle image update
        if (req.file) {
            // Remove old image if exists
            if (pickerPacker.image) {
                const oldImagePath = path.join(__dirname, '..', 'public', pickerPacker.image);
                if (fs.existsSync(oldImagePath)) {
                    fs.unlinkSync(oldImagePath);
                }
            }
            updateData.image = `/uploads/picker_packers/${req.file.filename}`;
        }

        // Update the picker packer
        const updatedPickerPacker = await PickerPacker.findByIdAndUpdate(
            id, 
            updateData,
            { new: true, runValidators: true }
        );

        res.status(200).json({ 
            success: true,
            data: updatedPickerPacker,
            msg: 'Picker packer updated successfully' 
        });
    } catch (error) {
        console.error('Error updating picker packer:', error);
        res.status(500).json({ 
            success: false,
            msg: error.message || 'Failed to update picker packer' 
        });
    }
};

// Delete a picker packer
exports.deletePickerPacker = async (req, res) => {
    try {
        // Check permission
        const hasPermission = await checkPermission(req.user.id, 'picker_packer_delete');
        if (!hasPermission) {
            return res.status(403).json({ error: 'You do not have permission to delete picker packers' });
        }

        const pickerPacker = await PickerPacker.findById(req.params.id);
        
        if (!pickerPacker) {
            return res.status(404).json({ error: 'Picker packer not found' });
        }

        // Check if the picker packer belongs to the user's store
        if (pickerPacker.store.toString() !== req.user.store.toString()) {
            return res.status(403).json({ error: 'You do not have permission to delete this picker packer' });
        }

        // Remove image if exists
        if (pickerPacker.image) {
            const imagePath = path.join(__dirname, '..', 'public', pickerPacker.image);
            if (fs.existsSync(imagePath)) {
                fs.unlinkSync(imagePath);
            }
        }

        await PickerPacker.findByIdAndDelete(req.params.id);
        res.status(200).json({ message: 'Picker packer deleted successfully' });
    } catch (error) {
        console.error('Error deleting picker packer:', error);
        res.status(500).json({ error: 'Failed to delete picker packer' });
    }
};

// Get picker packer statistics
exports.getPickerPackerStats = async (req, res) => {
    try {
        // Check permission
        const hasPermission = await checkPermission(req.user.id, 'picker_packer_view');
        if (!hasPermission) {
            return res.status(403).json({ error: 'You do not have permission to view picker packer statistics' });
        }

        const totalPickerPackers = await PickerPacker.countDocuments({ store: req.user.store });
        const activePickerPackers = await PickerPacker.countDocuments({ store: req.user.store, status: 'active' });
        const inactivePickerPackers = await PickerPacker.countDocuments({ store: req.user.store, status: 'inactive' });
        
        // Get picker packers by shift
        const morningShift = await PickerPacker.countDocuments({ store: req.user.store, shift: 'morning' });
        const eveningShift = await PickerPacker.countDocuments({ store: req.user.store, shift: 'evening' });
        const nightShift = await PickerPacker.countDocuments({ store: req.user.store, shift: 'night' });
        
        // Get top performers
        const topPerformers = await PickerPacker.find({ store: req.user.store })
            .sort({ performanceRating: -1, ordersProcessed: -1 })
            .limit(5);
            
        res.status(200).json({
            totalPickerPackers,
            activePickerPackers,
            inactivePickerPackers,
            shiftDistribution: {
                morning: morningShift,
                evening: eveningShift,
                night: nightShift
            },
            topPerformers
        });
    } catch (error) {
        console.error('Error fetching picker packer statistics:', error);
        res.status(500).json({ error: 'Failed to fetch picker packer statistics' });
    }
};