const Pharmacist = require('../models/Pharmacist');
const User = require('../models/User');
const { deleteFile, getUploadsPath } = require('../utils/fileUtils');
const path = require('path');
const fs = require('fs').promises;
const bcrypt = require('bcryptjs');
const mongoose = require('mongoose');

// Get all pharmacists with pagination and search
const getAllPharmacists = async (req, res) => {
  try {
    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 10;
    const skip = (page - 1) * limit;
    const search = req.query.search || '';
    const status = req.query.status || 'all';
    
    // Build query
    const query = {};
    
    // Filter by search term
    if (search) {
      query.$or = [
        { name: { $regex: search, $options: 'i' } },
        { email: { $regex: search, $options: 'i' } },
        { phone: { $regex: search, $options: 'i' } },
        { license_number: { $regex: search, $options: 'i' } }
      ];
    }
    
    // Filter by status
    if (status !== 'all') {
      query.status = status;
    }
    
    // For store managers, only show pharmacists from their store
    if (req.user.role === 'store_manager' && req.user.store) {
      query.store = req.user.store._id || req.user.store;
    }
    
    // Get total count for pagination
    const total = await Pharmacist.countDocuments(query);
    
    // Get pharmacists with pagination and populate store info
    const pharmacists = await Pharmacist.find(query)
      .populate('store', 'storeName _id')
      .sort({ createdAt: -1 })
      .skip(skip)
      .limit(limit);
    
    res.status(200).json({
      success: true,
      count: pharmacists.length,
      total,
      page,
      pages: Math.ceil(total / limit),
      data: pharmacists
    });
    
  } catch (error) {
    console.error('Error fetching pharmacists:', error);
    res.status(500).json({
      success: false,
      msg: 'Server error',
      error: error.message
    });
  }
};

// Get pharmacist by ID
const getPharmacistById = async (req, res) => {
  try {
    const pharmacist = await Pharmacist.findById(req.params.id)
      .populate('store', 'storeName _id')
      .populate('user', 'name email');

    if (!pharmacist) {
      return res.status(404).json({
        success: false,
        msg: 'Pharmacist not found'
      });
    }

    // Check if the requesting user has permission to view this pharmacist
    // Admin can view all, store manager can only view their store's pharmacists
    if (req.user.role === 'store_manager' && 
        pharmacist.store && 
        pharmacist.store._id.toString() !== req.user.store?._id?.toString() &&
        pharmacist.store.toString() !== req.user.store?.toString()) {
      return res.status(403).json({
        success: false,
        msg: 'Not authorized to view this pharmacist'
      });
    }

    res.status(200).json({
      success: true,
      data: pharmacist
    });
  } catch (error) {
    console.error('Error fetching pharmacist:', error);
    res.status(500).json({
      success: false,
      msg: 'Server error',
      error: error.message
    });
  }
};

// Create new pharmacist
const createPharmacist = async (req, res) => {
  try {
    let { 
      name, 
      email, 
      password, 
      phone, 
      license_number, 
      specialization, 
      experience, 
      status = 'active', 
      joining_date = new Date(),
      store // Store ID from request body (can be empty)
    } = req.body;
    
    // If store is not provided, try to get it from the authenticated user
    if (!store && req.user) {
      // For store managers, use their store if available
      if (req.user.role === 'store_manager' || req.user.role === 'admin') {
        if (req.user.store) {
          // If store is already populated or is an ID
          store = req.user.store._id?.toString() || req.user.store.toString();
        } else if (req.user._id) {
          // Try to find any store managed by this user
          const managedStore = await mongoose.model('Store').findOne({ 
            $or: [
              { manager: req.user._id },
              { 'managers.manager': req.user._id }
            ]
          }).select('_id').lean();
          
          if (managedStore) {
            store = managedStore._id.toString();
          } else if (req.user.role === 'admin') {
            // For admins, find the first active store or create a default one
            const defaultStore = await mongoose.model('Store').findOne({ status: 'active' }).select('_id').lean();
            if (defaultStore) {
              store = defaultStore._id.toString();
            }
          }
        }
      } 
      // For users with direct store assignment
      else if (req.user.store) {
        store = req.user.store._id?.toString() || req.user.store.toString();
      }
    }
    
    // Validation
    if (!name || !email || !password) {
      return res.status(400).json({
        success: false,
        msg: 'Name, email and password are required'
      });
    }

    // Normalize email
    const normalizedEmail = email.toLowerCase();

    // Check if email already exists in User collection
    const existingUser = await User.findOne({ email: normalizedEmail });
    if (existingUser) {
      return res.status(409).json({
        success: false,
        msg: 'Email already exists in the system'
      });
    }

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

    // Handle uploaded image
    let imagePath = null;
    if (req.file) {
      imagePath = `/uploads/pharmacists/${req.file.filename}`;
    }

    // Get the store ID from the authenticated user (store manager)
    let storeId = req.user?.store?._id || req.user?.store;
    
    // If no store ID from user, try to find or create one
    if (!storeId) {
      // First, try to find any active store
      const activeStore = await mongoose.model('Store').findOne({ status: 'active' }).select('_id').lean();
      
      if (activeStore) {
        storeId = activeStore._id;
      } 
      // If no active store and user is admin/manager, create a default one
      else if (req.user?.role === 'admin' || req.user?.role === 'store_manager') {
        try {
          const defaultStore = await mongoose.model('Store').create({
            storeName: 'Default Store',
            contactNumber: req.user.phone || '0000000000',
            email: req.user.email || 'default@store.com',
            address: 'Default address',
            city: 'Default City',
            state: 'Default State',
            country: 'Default Country',
            pincode: '000000',
            status: 'active',
            manager: req.user.role === 'store_manager' ? req.user._id : undefined,
            managers: req.user.role === 'store_manager' ? [{ manager: req.user._id }] : []
          });
          
          storeId = defaultStore._id;
        } catch (createError) {
          console.error('Error creating default store:', createError);
          return res.status(400).json({
            success: false,
            msg: 'Failed to create default store. Please contact an administrator.'
          });
        }
      } else {
        return res.status(400).json({
          success: false,
          msg: 'No store available. Please contact an administrator.'
        });
      }
    }

    // Validate store ID format and check if store exists
    if (!mongoose.Types.ObjectId.isValid(storeId)) {
      return res.status(400).json({
        success: false,
        msg: 'Invalid store ID format.'
      });
    }
    
    // Verify store exists
    const storeExists = await mongoose.model('Store').findById(storeId).countDocuments();
    if (!storeExists) {
      return res.status(400).json({
        success: false,
        msg: 'The specified store does not exist.'
      });
    }

    // Create user with pharmacist role and store reference
    const user = await User.create({
      _id: new mongoose.Types.ObjectId(), // Generate a new ObjectId for the user
      name,
      email: normalizedEmail,
      password: hashedPassword,
      phone,
      role: 'pharmacist',
      status: status === 'active',
      store: storeId,  // Set the store reference in the User model
      storeManager: req.user?._id  // Reference to the store manager who created this pharmacist
    });

    if (!user) {
      throw new Error('Failed to create user');
    }

    // Create pharmacist with the same ID as the user
    const pharmacistData = {
      _id: user._id, // Use the same ID as the user
      user: user._id,
      name,
      email: normalizedEmail,
      phone,
      license_number,
      specialization,
      experience: experience ? parseInt(experience) : 0,
      status,
      joining_date: new Date(joining_date),
      store: new mongoose.Types.ObjectId(storeId), // Ensure store is a valid ObjectId
      image: imagePath,
      created_at: new Date(),
      updated_at: new Date()
    };

    // Remove any undefined values
    const cleanData = Object.fromEntries(
      Object.entries(pharmacistData).filter(([_, v]) => v !== undefined)
    );

    // Create pharmacist document directly using the model
    const newPharmacist = await mongoose.model('Pharmacist').create(cleanData);
    
    if (!newPharmacist) {
      // Clean up user if pharmacist creation fails
      await User.findByIdAndDelete(user._id);
      throw new Error('Failed to create pharmacist');
    }
    
    res.status(201).json({
      success: true,
      data: newPharmacist,
      msg: 'Pharmacist created successfully'
    });
  } catch (error) {
    console.error('Error creating pharmacist:', error);
    
    // Handle specific errors
    if (error.code === 11000 && error.keyPattern && error.keyPattern.email) {
      return res.status(409).json({
        success: false,
        msg: 'Email already exists in the system'
      });
    }

    // Handle validation errors
    if (error.name === 'ValidationError') {
      return res.status(400).json({
        success: false,
        msg: Object.values(error.errors).map(err => err.message).join(', ')
      });
    }

    // Handle other errors
    res.status(500).json({
      success: false,
      msg: error.message || 'Error creating pharmacist'
    });
  }
};

// Update pharmacist
const updatePharmacist = async (req, res) => {
  try {
    const { id } = req.params;
    const { 
      name, 
      email, 
      password, 
      phone, 
      license_number, 
      specialization, 
      experience, 
      status, 
      joining_date 
    } = req.body;
    
    // Check if pharmacist exists
    const existingPharmacist = await Pharmacist.findById(id);
    if (!existingPharmacist) {
      return res.status(404).json({
        success: false,
        msg: 'Pharmacist not found'
      });
    }

    // Check if user has permission (admin or managing the same store)
    if (req.user && req.user.role === 'store_manager') {
      // Get store IDs in a comparable format
      const pharmacistStoreId = existingPharmacist.store?._id?.toString() || existingPharmacist.store?.toString();
      const userStoreId = req.user.store?._id?.toString() || req.user.store?.toString();
      
      console.log('Authorization check:', {
        pharmacistStoreId,
        userStoreId,
        userRole: req.user.role,
        storeManagerId: req.user._id
      });

      if (!pharmacistStoreId || !userStoreId || pharmacistStoreId !== userStoreId) {
        return res.status(403).json({
          success: false,
          msg: 'Not authorized to update this pharmacist. You can only manage pharmacists in your store.'
        });
      }
    }

    // Handle image update
    let imagePath = existingPharmacist.image; // Keep existing image by default
    let oldImagePath = null;

    // If a new file is uploaded
    if (req.file) {
      // Set new image path
      imagePath = `/uploads/pharmacists/${req.file.filename}`;
      
      // Mark old image for deletion if it exists
      if (existingPharmacist.image) {
        const filename = existingPharmacist.image.split('/').pop();
        oldImagePath = path.join(getUploadsPath(), 'pharmacists', filename);
      }
    } 
    // If image is being removed
    else if (req.body.removeImage === 'true') {
      // Mark old image for deletion
      if (existingPharmacist.image) {
        const filename = existingPharmacist.image.split('/').pop();
        oldImagePath = path.join(getUploadsPath(), 'pharmacists', filename);
      }
      imagePath = ''; // Clear the image path
    }

    // Delete old image file if needed
    if (oldImagePath) {
      try {
        await deleteFile(oldImagePath);
      } catch (error) {
        console.error('Error deleting old pharmacist image:', error);
        // Don't fail the request if image deletion fails
      }
    }
    
    // Check if email already exists in User collection (for updates)
    if (email && email.toLowerCase() !== existingPharmacist.email?.toLowerCase()) {
      const existingUser = await User.findOne({ 
        email: email.toLowerCase(),
        _id: { $ne: existingPharmacist._id } // Exclude current pharmacist
      });
      
      if (existingUser) {
        return res.status(409).json({
          success: false,
          msg: 'Email already exists'
        });
      }
    }

    // Prepare update data
    const updateData = {
      name,
      email,
      phone,
      license_number,
      specialization,
      status,
      image: imagePath,
      joining_date
    };

    // Only include experience if provided
    if (experience !== undefined) {
      updateData.experience = parseInt(experience);
    }

    // Update password if provided
    if (password) {
      const salt = await bcrypt.genSalt(10);
      updateData.password = await bcrypt.hash(password, salt);
    }

    const updatedPharmacist = await Pharmacist.updatePharmacist(id, updateData);

    res.json({
      success: true,
      data: updatedPharmacist,
      msg: 'Pharmacist updated successfully'
    });
  } catch (error) {
    console.error('Error updating pharmacist:', error);

    // Handle specific validation errors
    if (error.message === 'Email already exists') {
      return res.status(409).json({
        success: false,
        msg: error.message
      });
    }

    res.status(500).json({
      success: false,
      msg: error.message || 'Error updating pharmacist'
    });
  }
};

// Delete pharmacist
const deletePharmacist = async (req, res) => {
  try {
    const { id } = req.params;
    
    // Check if pharmacist exists
    const existingPharmacist = await Pharmacist.findById(id);
    if (!existingPharmacist) {
      return res.status(404).json({
        success: false,
        msg: 'Pharmacist not found'
      });
    }

    // Check if user has permission (admin or managing the same store)
    if (req.user && req.user.role === 'store_manager' && 
        existingPharmacist.store.toString() !== req.user.store.toString()) {
      return res.status(403).json({
        success: false,
        msg: 'Not authorized to delete this pharmacist'
      });
    }

    // Delete associated image if exists
    if (existingPharmacist.image) {
      try {
        const filename = existingPharmacist.image.split('/').pop();
        const imagePath = path.join(getUploadsPath(), 'pharmacists', filename);
        await deleteFile(imagePath);
      } catch (error) {
        console.error('Error deleting pharmacist image:', error);
        // Don't fail the request if image deletion fails
      }
    }

    await Pharmacist.deletePharmacist(id);
    
    res.json({
      success: true,
      msg: 'Pharmacist deleted successfully'
    });
  } catch (error) {
    console.error('Error deleting pharmacist:', error);
    res.status(500).json({
      success: false,
      msg: error.message || 'Error deleting pharmacist'
    });
  }
};

// Get pharmacist statistics
const getPharmacistStatistics = async (req, res) => {
  try {
    const totalPharmacists = await Pharmacist.countDocuments();
    const activePharmacists = await Pharmacist.countDocuments({ status: 'active' });
    const inactivePharmacists = await Pharmacist.countDocuments({ status: 'inactive' });
    const pendingPharmacists = await Pharmacist.countDocuments({ isVerified: false });

    res.status(200).json({
      success: true,
      data: {
        total: totalPharmacists,
        active: activePharmacists,
        inactive: inactivePharmacists,
        pending: pendingPharmacists,
      },
    });
  } catch (error) {
    console.error('Error getting pharmacist statistics:', error);
    res.status(500).json({
      success: false,
      message: 'Error getting pharmacist statistics',
      error: error.message,
    });
  }
};

// @desc    Get orders requiring prescription verification
// @route   GET /api/v1/pharmacist/prescriptions/orders
// @access  Private (Pharmacist)
const getPrescriptionOrders = async (req, res) => {
  try {
    // This is a placeholder - implement your actual logic to get orders needing verification
    // For example: const orders = await Order.find({ requiresPrescription: true, prescriptionStatus: 'pending' });
    
    res.status(200).json({
      success: true,
      count: 0,
      data: []
    });
  } catch (error) {
    console.error('Error getting prescription orders:', error);
    res.status(500).json({
      success: false,
      message: 'Error getting prescription orders',
      error: error.message,
    });
  }
};

// @desc    Verify/Reject prescription for an order
// @route   POST /api/v1/pharmacist/prescriptions/orders/:orderId/verify
// @access  Private (Pharmacist)
const verifyPrescription = async (req, res) => {
  try {
    const { orderId } = req.params;
    const { status, notes } = req.body; // status: 'approved' or 'rejected'
    
    // This is a placeholder - implement your actual verification logic
    // For example:
    // const order = await Order.findById(orderId);
    // if (!order) {
    //   return res.status(404).json({ success: false, message: 'Order not found' });
    // }
    // order.prescriptionStatus = status;
    // order.prescriptionVerifiedBy = req.user.id;
    // order.prescriptionVerificationNotes = notes;
    // await order.save();
    
    res.status(200).json({
      success: true,
      message: `Prescription ${status} successfully`,
      data: { orderId, status, verifiedBy: req.user.id }
    });
  } catch (error) {
    console.error('Error verifying prescription:', error);
    res.status(500).json({
      success: false,
      message: 'Error verifying prescription',
      error: error.message,
    });
  }
};

// @desc    Assign stores to pharmacist
// @route   POST /api/v1/pharmacist/:id/assign-stores
// @access  Private (Admin)
// @desc    Get assigned stores for a pharmacist
// @route   GET /api/v1/pharmacist/:id/assigned-stores
// @access  Private (Admin, Pharmacist)
const getAssignedStores = async (req, res) => {
  try {
    const { id } = req.params;
    
    // This is a placeholder - implement your actual logic to get assigned stores
    // For example:
    // const pharmacist = await Pharmacist.findById(id).populate('assignedStores');
    // if (!pharmacist) {
    //   return res.status(404).json({ success: false, message: 'Pharmacist not found' });
    // }
    
    res.status(200).json({
      success: true,
      count: 0,
      data: []
    });
  } catch (error) {
    console.error('Error getting assigned stores:', error);
    res.status(500).json({
      success: false,
      message: 'Error getting assigned stores',
      error: error.message,
    });
  }
};

// @desc    Assign stores to pharmacist
// @route   POST /api/v1/pharmacist/:id/assign-stores
// @access  Private (Admin)
const assignStores = async (req, res) => {
  try {
    const { id } = req.params;
    const { storeIds } = req.body; // Array of store IDs
    
    // This is a placeholder - implement your actual store assignment logic
    // For example:
    // const pharmacist = await Pharmacist.findByIdAndUpdate(
    //   id,
    //   { $addToSet: { assignedStores: { $each: storeIds } } },
    //   { new: true, runValidators: true }
    // );
    
    res.status(200).json({
      success: true,
      message: 'Stores assigned to pharmacist successfully',
      data: { pharmacistId: id, assignedStores: storeIds }
    });
  } catch (error) {
    console.error('Error assigning stores to pharmacist:', error);
    res.status(500).json({
      success: false,
      message: 'Error assigning stores to pharmacist',
      error: error.message,
    });
  }
};

module.exports = {
  getAllPharmacists,
  getPharmacistById,
  createPharmacist,
  updatePharmacist,
  deletePharmacist,
  getPharmacistStatistics,
  getPrescriptionOrders,
  verifyPrescription,
  assignStores,
  getAssignedStores
};