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

// Get all roles (HIERARCHICAL FILTERING)
exports.getAllRoles = async (req, res, next) => {
  try {
    const role = await Role.findById(req.user.roleId).select("name");
    if (!role) return res.status(401).json({ success: false, message: "Unauthorized" });

    const queryMap = {
      root: { name: { $ne: "root" } },
      super_admin: { name: { $nin: ["root", "super_admin"] } },
      admin: { name: { $nin: ["root", "super_admin", "admin"] }, isSystemRole: false },
    };

    const query = queryMap[role.name];
    if (!query) return res.status(403).json({ success: false, message: "Insufficient permissions" });

    const roles = await Role.find(query)
      .populate("modulePermissions.moduleId", "name displayName icon category")
      .sort({ level: 1 });

    res.json({ success: true, count: roles.length, data: roles });
  } catch (e) {
    next(e);
  }
};


// Get single role (HIERARCHICAL ACCESS)
exports.getRole = async (req, res, next) => {
  try {
    const currentUserRole = await Role.findById(req.user.roleId);
    const role = await Role.findById(req.params.id)
      .populate('modulePermissions.moduleId', 'name displayName icon category actions');
    
    if (!role) {
      return res.status(404).json({
        success: false,
        message: 'Role not found'
      });
    }
    
    // Access control based on hierarchy
    const roleHierarchy = ['root', 'super_admin', 'admin'];
    const currentRoleIndex = roleHierarchy.indexOf(currentUserRole.name);
    const targetRoleIndex = roleHierarchy.indexOf(role.name);
    
    // Can only view roles BELOW your level (or same level for non-system roles)
    if (targetRoleIndex < currentRoleIndex) {
      return res.status(403).json({
        success: false,
        message: `Cannot access ${role.name} role`
      });
    }
    
    // Root cannot view super_admin, Super Admin cannot view root
    if (currentUserRole.name === 'root' && role.name === 'super_admin') {
      return res.status(403).json({
        success: false,
        message: 'Access denied to super admin role'
      });
    }
    
    res.status(200).json({
      success: true,
      data: role
    });
  } catch (error) {
    next(error);
  }
};

// Create new role (scoped to company users only)
exports.createRole = async (req, res, next) => {
  try {
    const currentUserRole = await Role.findById(req.user.roleId);
    
    // Only root and super_admin can create roles
    if (!['root', 'super_admin'].includes(currentUserRole.name)) {
      return res.status(403).json({
        success: false,
        message: 'Insufficient permissions to create roles'
      });
    }
    
    const { name, displayName, description, level, scope, modulePermissions, specialPermissions } = req.body;
    
    // Prevent creating root/super_admin roles
    if (['root', 'super_admin'].includes(name.toLowerCase())) {
      return res.status(400).json({
        success: false,
        message: `Cannot create ${name.toLowerCase()} role`
      });
    }
    
    // Check if role already exists
    const existingRole = await Role.findOne({ name: name.toLowerCase() });
    if (existingRole) {
      return res.status(400).json({
        success: false,
        message: 'Role with this name already exists'
      });
    }
    
    // Validate modules exist
    const moduleIds = modulePermissions.map(mp => mp.moduleId);
    const modules = await Module.find({ _id: { $in: moduleIds } });
    
    if (modules.length !== moduleIds.length) {
      return res.status(400).json({
        success: false,
        message: 'One or more invalid module IDs'
      });
    }
    
    // Create role
    const role = await Role.create({
      name: name.toLowerCase(),
      displayName,
      description,
      level,
      scope: scope || 'company', // Default to company scope
      modulePermissions,
      specialPermissions: specialPermissions || [],
      isSystemRole: false,
      createdBy: req.user._id
    });
    
    // Log activity - use first company
    await ActivityLog.create({
      userId: req.user._id,
      companyId: req.user.companies?.[0]?._id || null,
      action: 'create',
      module: 'roles',
      entityType: 'Role',
      entityId: role._id,
      description: `Created new role: ${role.displayName}`
    });
    
    const populatedRole = await Role.findById(role._id)
      .populate('modulePermissions.moduleId', 'name displayName icon');
    
    res.status(201).json({
      success: true,
      message: 'Role created successfully',
      data: populatedRole
    });
    
  } catch (error) {
    next(error);
  }
};

// Update role (same hierarchy rules)
exports.updateRole = async (req, res, next) => {
  try {
    const currentUserRole = await Role.findById(req.user.roleId);
    const { id } = req.params;
    
    // Find role to update
    const role = await Role.findById(id);
    if (!role) {
      return res.status(404).json({
        success: false,
        message: 'Role not found'
      });
    }
    
    // Hierarchy check (same as getRole)
    const roleHierarchy = ['root', 'super_admin', 'admin'];
    const currentRoleIndex = roleHierarchy.indexOf(currentUserRole.name);
    const targetRoleIndex = roleHierarchy.indexOf(role.name);
    
    if (targetRoleIndex < currentRoleIndex) {
      return res.status(403).json({
        success: false,
        message: `Cannot modify ${role.name} role`
      });
    }
    
    const updates = req.body;
    
    // Prevent changing system roles
    if (role.isSystemRole && ['root', 'super_admin'].includes(role.name)) {
      return res.status(403).json({
        success: false,
        message: `Cannot modify ${role.name} role`
      });
    }
    
    const updatedRole = await Role.findByIdAndUpdate(
      id,
      updates,
      { new: true, runValidators: true }
    ).populate('modulePermissions.moduleId', 'name displayName icon');
    
    await ActivityLog.create({
      userId: req.user._id,
      companyId: req.user.companies?.[0]?._id || null,
      action: 'update',
      module: 'roles',
      entityType: 'Role',
      entityId: updatedRole._id,
      description: `Updated role: ${updatedRole.displayName}`,
      changes: updates
    });
    
    res.status(200).json({
      success: true,
      message: 'Role updated successfully',
      data: updatedRole
    });
    
  } catch (error) {
    next(error);
  }
};

// Delete role (same hierarchy + user check)
exports.deleteRole = async (req, res, next) => {
  try {
    const currentUserRole = await Role.findById(req.user.roleId);
    const { id } = req.params;
    
    const role = await Role.findById(id);
    if (!role) {
      return res.status(404).json({
        success: false,
        message: 'Role not found'
      });
    }
    
    // Hierarchy check
    const roleHierarchy = ['root', 'super_admin', 'admin'];
    const currentRoleIndex = roleHierarchy.indexOf(currentUserRole.name);
    const targetRoleIndex = roleHierarchy.indexOf(role.name);
    
    if (targetRoleIndex < currentRoleIndex) {
      return res.status(403).json({
        success: false,
        message: `Cannot delete ${role.name} role`
      });
    }
    
    // Prevent deleting system roles
    if (role.isSystemRole) {
      return res.status(403).json({
        success: false,
        message: 'Cannot delete system roles'
      });
    }
    
    // Check if role is assigned to users
    const usersWithRole = await User.countDocuments({ roleId: id });
    if (usersWithRole > 0) {
      return res.status(400).json({
        success: false,
        message: `Cannot delete role. ${usersWithRole} user(s) assigned.`
      });
    }
    
    await Role.findByIdAndDelete(id);
    
    await ActivityLog.create({
      userId: req.user._id,
      companyId: req.user.companies?.[0]?._id || null,
      action: 'delete',
      module: 'roles',
      entityType: 'Role',
      entityId: role._id,
      description: `Deleted role: ${role.displayName}`
    });
    
    res.status(200).json({
      success: true,
      message: 'Role deleted successfully'
    });
  } catch (error) {
    next(error);
  }
};

// Keep other methods unchanged (getAvailableModules, cloneRole)
exports.getAvailableModules = async (req, res, next) => {
  try {
    const modules = await Module.find({ isActive: true })
      .select('name displayName description icon category actions')
      .sort({ order: 1 });
    
    res.status(200).json({
      success: true,
      count: modules.length,
      data: modules
    });
  } catch (error) {
    next(error);
  }
};

exports.cloneRole = async (req, res, next) => {
  try {
    const currentUserRole = await Role.findById(req.user.roleId);
    
    if (!['root', 'super_admin'].includes(currentUserRole.name)) {
      return res.status(403).json({
        success: false,
        message: 'Insufficient permissions to clone roles'
      });
    }
    
    const { id } = req.params;
    const { name, displayName } = req.body;
    
    if (!name || !displayName) {
      return res.status(400).json({
        success: false,
        message: 'Name and displayName are required'
      });
    }
    
    const originalRole = await Role.findById(id);
    if (!originalRole) {
      return res.status(404).json({
        success: false,
        message: 'Role not found'
      });
    }
    
    const existingRole = await Role.findOne({ name: name.toLowerCase() });
    if (existingRole) {
      return res.status(400).json({
        success: false,
        message: 'Role with this name already exists'
      });
    }
    
    const clonedRole = await Role.create({
      name: name.toLowerCase(),
      displayName,
      description: originalRole.description,
      level: originalRole.level,
      scope: originalRole.scope,
      modulePermissions: originalRole.modulePermissions,
      specialPermissions: originalRole.specialPermissions,
      isSystemRole: false,
      createdBy: req.user._id
    });
    
    const populatedRole = await Role.findById(clonedRole._id)
      .populate('modulePermissions.moduleId', 'name displayName icon');
    
    res.status(201).json({
      success: true,
      message: 'Role cloned successfully',
      data: populatedRole
    });
  } catch (error) {
    next(error);
  }
};