const Module = require('../models/Module');
const Role = require('../models/Role');
const ActivityLog = require('../models/ActivityLog');

// Get all modules
exports.getAllModules = async (req, res, next) => {
  try {
    const { category, isActive, search, page = 1, limit = 50 } = req.query;
    
    // Build query
    let query = {};
    
    // Filter by category
    if (category) {
      query.category = category;
    }
    
    // Filter by active status
    if (isActive !== undefined) {
      query.isActive = isActive === 'true';
    }
    
    // Search by name or display name
    if (search) {
      query.$or = [
        { name: { $regex: search, $options: 'i' } },
        { displayName: { $regex: search, $options: 'i' } }
      ];
    }
    
    // Pagination
    const skip = (page - 1) * limit;
    
    const modules = await Module.find(query)
      .populate('createdBy', 'firstName lastName email')
      .sort({ order: 1 })
      .limit(parseInt(limit))
      .skip(skip);
    
    const total = await Module.countDocuments(query);
    
    // Group by category
    const groupedByCategory = modules.reduce((acc, module) => {
      if (!acc[module.category]) {
        acc[module.category] = [];
      }
      acc[module.category].push(module);
      return acc;
    }, {});
    
    res.status(200).json({
      success: true,
      count: modules.length,
      total,
      page: parseInt(page),
      pages: Math.ceil(total / limit),
      data: modules,
      groupedByCategory
    });
  } catch (error) {
    next(error);
  }
};

// Get single module
exports.getModule = async (req, res, next) => {
  try {
    const { id } = req.params;
    
    const module = await Module.findById(id)
      .populate('createdBy', 'firstName lastName email');
    
    if (!module) {
      return res.status(404).json({
        success: false,
        message: 'Module not found'
      });
    }
    
    // Get roles that have access to this module
    const rolesWithAccess = await Role.find({
      'modulePermissions.moduleId': id
    }).select('name displayName modulePermissions');
    
    // Extract permissions for this module from each role
    const rolePermissions = rolesWithAccess.map(role => {
      const modulePermission = role.modulePermissions.find(
        mp => mp.moduleId.toString() === id
      );
      return {
        roleId: role._id,
        roleName: role.name,
        roleDisplayName: role.displayName,
        permissions: modulePermission ? Object.fromEntries(modulePermission.permissions) : {}
      };
    });
    
    res.status(200).json({
      success: true,
      data: {
        ...module.toObject(),
        rolePermissions
      }
    });
  } catch (error) {
    next(error);
  }
};

// Get modules by category
exports.getModulesByCategory = async (req, res, next) => {
  try {
    const modules = await Module.find({ isActive: true })
      .sort({ order: 1 });
    
    // Group by category
    const categories = {
      admin: [],
      crm: [],
      workflow: [],
      reports: [],
      analytics: [],
      settings: []
    };
    
    modules.forEach(module => {
      if (categories[module.category]) {
        categories[module.category].push(module);
      }
    });
    
    res.status(200).json({
      success: true,
      data: categories
    });
  } catch (error) {
    next(error);
  }
};

// Create module
exports.createModule = async (req, res, next) => {
  try {
    const {
      name,
      displayName,
      description,
      icon,
      category,
      route,
      order,
      isActive,
      actions
    } = req.body;
    
    // Check if module name already exists
    const existingModule = await Module.findOne({ name: name.toLowerCase() });
    if (existingModule) {
      return res.status(400).json({
        success: false,
        message: 'Module with this name already exists'
      });
    }
    
    // Validate actions
    const validActions = ['read', 'create', 'edit', 'delete', 'approve', 'reject', 'review', 'export', 'import', 'assign', 'resolve', 'schedule', 'share'];
    const invalidActions = actions.filter(action => !validActions.includes(action.name));
    
    if (invalidActions.length > 0) {
      return res.status(400).json({
        success: false,
        message: `Invalid action(s): ${invalidActions.map(a => a.name).join(', ')}`
      });
    }
    
    // Create module
    const module = await Module.create({
      name: name.toLowerCase(),
      displayName,
      description,
      icon,
      category,
      route,
      order,
      isActive,
      actions,
      createdBy: req.user._id
    });
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      action: 'create',
      module: 'modules',
      entityType: 'Module',
      entityId: module._id,
      description: `Created module: ${module.displayName}`,
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    const populatedModule = await Module.findById(module._id)
      .populate('createdBy', 'firstName lastName email');
    
    res.status(201).json({
      success: true,
      message: 'Module created successfully',
      data: populatedModule
    });
  } catch (error) {
    next(error);
  }
};

// Update module
exports.updateModule = async (req, res, next) => {
  try {
    const { id } = req.params;
    const updates = req.body;
    
    // Don't allow updating module name
    delete updates.name;
    
    const module = await Module.findByIdAndUpdate(
      id,
      updates,
      { new: true, runValidators: true }
    ).populate('createdBy', 'firstName lastName email');
    
    if (!module) {
      return res.status(404).json({
        success: false,
        message: 'Module not found'
      });
    }
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      action: 'update',
      module: 'modules',
      entityType: 'Module',
      entityId: module._id,
      description: `Updated module: ${module.displayName}`,
      changes: updates,
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    res.status(200).json({
      success: true,
      message: 'Module updated successfully',
      data: module
    });
  } catch (error) {
    next(error);
  }
};

// Delete module
exports.deleteModule = async (req, res, next) => {
  try {
    const { id } = req.params;
    
    const module = await Module.findById(id);
    
    if (!module) {
      return res.status(404).json({
        success: false,
        message: 'Module not found'
      });
    }
    
    // Check if module is used in any roles
    const rolesUsingModule = await Role.countDocuments({
      'modulePermissions.moduleId': id
    });
    
    if (rolesUsingModule > 0) {
      return res.status(400).json({
        success: false,
        message: `Cannot delete module. ${rolesUsingModule} role(s) are using this module. Please remove module from roles first.`
      });
    }
    
    await Module.findByIdAndDelete(id);
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      action: 'delete',
      module: 'modules',
      entityType: 'Module',
      entityId: module._id,
      description: `Deleted module: ${module.displayName}`,
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    res.status(200).json({
      success: true,
      message: 'Module deleted successfully'
    });
  } catch (error) {
    next(error);
  }
};

// Toggle module status (activate/deactivate)
exports.toggleModuleStatus = async (req, res, next) => {
  try {
    const { id } = req.params;
    
    const module = await Module.findById(id);
    
    if (!module) {
      return res.status(404).json({
        success: false,
        message: 'Module not found'
      });
    }
    
    module.isActive = !module.isActive;
    await module.save();
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      action: 'update',
      module: 'modules',
      entityType: 'Module',
      entityId: module._id,
      description: `${module.isActive ? 'Activated' : 'Deactivated'} module: ${module.displayName}`,
      changes: { isActive: module.isActive },
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    res.status(200).json({
      success: true,
      message: `Module ${module.isActive ? 'activated' : 'deactivated'} successfully`,
      data: module
    });
  } catch (error) {
    next(error);
  }
};

// Reorder modules
exports.reorderModules = async (req, res, next) => {
  try {
    const { modules } = req.body; // Array of { id, order }
    
    if (!Array.isArray(modules)) {
      return res.status(400).json({
        success: false,
        message: 'Modules must be an array'
      });
    }
    
    // Update order for each module
    const updatePromises = modules.map(({ id, order }) => 
      Module.findByIdAndUpdate(id, { order }, { new: true })
    );
    
    await Promise.all(updatePromises);
    
    // Get updated modules
    const updatedModules = await Module.find().sort({ order: 1 });
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      action: 'update',
      module: 'modules',
      description: `Reordered modules`,
      changes: { modules },
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    res.status(200).json({
      success: true,
      message: 'Modules reordered successfully',
      data: updatedModules
    });
  } catch (error) {
    next(error);
  }
};

// Get module statistics
exports.getModuleStats = async (req, res, next) => {
  try {
    const totalModules = await Module.countDocuments();
    const activeModules = await Module.countDocuments({ isActive: true });
    const inactiveModules = await Module.countDocuments({ isActive: false });
    
    // Count by category
    const modulesByCategory = await Module.aggregate([
      {
        $group: {
          _id: '$category',
          count: { $sum: 1 },
          active: {
            $sum: { $cond: ['$isActive', 1, 0] }
          }
        }
      },
      { $sort: { count: -1 } }
    ]);
    
    // Count total actions
    const actionStats = await Module.aggregate([
      { $unwind: '$actions' },
      {
        $group: {
          _id: '$actions.name',
          count: { $sum: 1 }
        }
      },
      { $sort: { count: -1 } }
    ]);
    
    res.status(200).json({
      success: true,
      data: {
        overview: {
          total: totalModules,
          active: activeModules,
          inactive: inactiveModules
        },
        byCategory: modulesByCategory,
        actionStats
      }
    });
  } catch (error) {
    next(error);
  }
};

// Get available actions
exports.getAvailableActions = async (req, res, next) => {
  try {
    const actions = [
      { name: 'read', displayName: 'View/Read', description: 'View and read data' },
      { name: 'create', displayName: 'Create', description: 'Create new records' },
      { name: 'edit', displayName: 'Edit/Update', description: 'Edit existing records' },
      { name: 'delete', displayName: 'Delete', description: 'Delete records' },
      { name: 'approve', displayName: 'Approve', description: 'Approve items (workflow)' },
      { name: 'reject', displayName: 'Reject', description: 'Reject items (workflow)' },
      { name: 'review', displayName: 'Review', description: 'Review items (workflow)' },
      { name: 'export', displayName: 'Export', description: 'Export/Download data' },
      { name: 'import', displayName: 'Import', description: 'Import data in bulk' },
      { name: 'assign', displayName: 'Assign', description: 'Assign items to users' },
      { name: 'resolve', displayName: 'Resolve', description: 'Resolve/Close items' },
      { name: 'schedule', displayName: 'Schedule', description: 'Schedule automated actions' },
      { name: 'share', displayName: 'Share', description: 'Share items with others' }
    ];
    
    res.status(200).json({
      success: true,
      count: actions.length,
      data: actions
    });
  } catch (error) {
    next(error);
  }
};

// Get module categories
exports.getModuleCategories = async (req, res, next) => {
  try {
    const categories = [
      { value: 'admin', label: 'Administration', description: 'User, role, and company management' },
      { value: 'crm', label: 'CRM', description: 'Customer relationship management' },
      { value: 'workflow', label: 'Workflow', description: 'Maker-Checker-Verifier workflows' },
      { value: 'reports', label: 'Reports', description: 'Business reports and insights' },
      { value: 'analytics', label: 'Analytics', description: 'Analytics and dashboards' },
      { value: 'settings', label: 'Settings', description: 'System and configuration settings' }
    ];
    
    // Add count for each category
    const categoriesWithCount = await Promise.all(
      categories.map(async (cat) => {
        const count = await Module.countDocuments({ category: cat.value });
        const activeCount = await Module.countDocuments({ category: cat.value, isActive: true });
        return {
          ...cat,
          count,
          activeCount
        };
      })
    );
    
    res.status(200).json({
      success: true,
      data: categoriesWithCount
    });
  } catch (error) {
    next(error);
  }
};