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

exports.getAllUsers = async (req, res, next) => {
  try {
    const {
      companyId,
      roleId: filterRoleId,
      status,
      search,
      page = 1,
      limit = 10,
      sortBy = 'createdAt',
      sortOrder = 'desc'
    } = req.query;

    const role = await Role.findById(req.user.roleId);
    let query = { _id: { $ne: req.user._id } };

    // ALWAYS exclude root users from list (root can only be fetched by ID)
    const rootRole = await Role.findOne({ name: 'root' });
    if (rootRole) {
      query.roleId = { $ne: rootRole._id };
    }

    // Handle role scopes
    if (role.scope === 'global') {
      // Super Admin: Can see all users except root and themselves
      if (companyId) query.companies = companyId;
    } else if (role.scope === 'company') {
      // Admin: Can only see users in their companies
      // Get all global roles to exclude
      const globalRoles = await Role.find({ scope: 'global' }).select('_id');
      const globalRoleIds = globalRoles.map(r => r._id.toString());

      const excludedRoleIds = [...globalRoleIds];
      
      // If the current user is an admin, they should not see other admin users
      if (role.name === 'admin') {
        excludedRoleIds.push(role._id.toString());
      }

      query.roleId = { ...query.roleId, $nin: excludedRoleIds };

      // Apply company restriction
      if (companyId) {
        // Ensure requested companyId is one the user has access to
        const userCompanyIds = req.user.companies.map(c => 
          typeof c === 'object' && c._id ? c._id.toString() : c.toString()
        );
        
        if (!userCompanyIds.includes(companyId.toString())) {
          return res.status(403).json({
            success: false,
            message: 'Access denied: You do not have access to this company'
          });
        }
        query.companies = companyId;
      } else {
        // Fallback to all user's companies
        query.companies = { $in: req.user.companies };
      }
    } else if (role.scope === 'partner') {
      // Channel Partner: Cannot see any users
      query._id = { $ne: req.user._id, $exists: false };
    }

    // Additional filters from query params
    if (filterRoleId) {
      // If user is company scoped, ensure they aren't trying to fetch global roles
      if (role.scope === 'company') {
        const targetRole = await Role.findById(filterRoleId);
        if (targetRole && targetRole.scope === 'global') {
          return res.status(403).json({
            success: false,
            message: 'Access denied: Cannot filter by global roles'
          });
        }
      }
      query.roleId = { ...query.roleId, $eq: filterRoleId };
    }

    if (status && status !== 'all') {
      query.status = status;
    }

    // Search functionality
    if (search && search.trim()) {
      const searchRegex = new RegExp(search.trim(), 'i');
      query.$or = [
        { firstName: searchRegex },
        { lastName: searchRegex },
        { email: searchRegex },
        { phone: searchRegex }
      ];
    }

    // Pagination
    const pageNum = Math.max(1, parseInt(page));
    const limitNum = Math.max(1, parseInt(limit));
    const skip = (pageNum - 1) * limitNum;

    // Sorting
    const sort = {};
    sort[sortBy] = sortOrder === 'asc' ? 1 : -1;

    const [users, totalUsers] = await Promise.all([
      User.find(query)
        .populate('companies', 'name code')
        .populate('roleId')
        .populate('createdBy', 'firstName lastName email')
        .populate('updatedBy', 'firstName lastName email')
        .select('-password -refreshToken')
        .sort(sort)
        .limit(limitNum)
        .skip(skip)
        .lean(),
      User.countDocuments(query)
    ]);

    res.status(200).json({
      success: true,
      data: {
        users,
        pagination: {
          currentPage: pageNum,
          totalPages: Math.ceil(totalUsers / limitNum),
          totalUsers,
          limit: limitNum
        }
      }
    });

  } catch (error) {
    next(error);
  }
};

exports.getUserById = async (req, res, next) => {
  try {
    const { id } = req.params;
    const role = await Role.findById(req.user.roleId);

    // Find the user
    const user = await User.findById(id)
      .populate('companies', 'name code')
      .populate('roleId')
      .populate('createdBy', 'firstName lastName email')
      .populate('updatedBy', 'firstName lastName email')
      .select('-password -refreshToken');

    if (!user) {
      return res.status(404).json({
        success: false,
        message: 'User not found'
      });
    }

    // Check access permissions
    const userRole = await Role.findById(user.roleId);

    // Only root or super admin can view root users
    if (userRole.name === 'root' && !['root', 'super_admin'].includes(role.name)) {
      return res.status(403).json({
        success: false,
        message: 'Access denied'
      });
    }

    // Admin can only view users in their companies
    if (role.scope === 'company') {
      if (userRole.scope === 'global') {
        return res.status(403).json({
          success: false,
          message: 'Access denied'
        });
      }

      // If the current user is an admin, they cannot view other admins
      if (role.name === 'admin' && userRole.name === 'admin' && user._id.toString() !== req.user._id.toString()) {
        return res.status(403).json({
          success: false,
          message: 'Access denied: Cannot view other admin users'
        });
      }

      // Check if user has at least one company in common
      const hasCommonCompany = user.companies.some(company =>
        req.user.companies.some(userCompany =>
          userCompany.toString() === company._id.toString()
        )
      );

      if (!hasCommonCompany && user.companies.length > 0) {
        return res.status(403).json({
          success: false,
          message: 'Access denied'
        });
      }
    }

    // Channel Partner can only view themselves
    if (role.scope === 'partner' && user._id.toString() !== req.user._id.toString()) {
      return res.status(403).json({
        success: false,
        message: 'Access denied'
      });
    }

    res.status(200).json({
      success: true,
      data: user
    });
  } catch (error) {
    next(error);
  }
};

exports.createUser = async (req, res, next) => {
  try {
    const { email, password, firstName, lastName, phone, roleId, companies } = req.body;

    // Check if user already exists
    const existingUser = await User.findOne({ email });
    if (existingUser) {
      return res.status(400).json({
        success: false,
        message: 'User with this email already exists'
      });
    }

    // Verify role exists
    const targetRole = await Role.findById(roleId);
    if (!targetRole) {
      return res.status(400).json({
        success: false,
        message: 'Invalid role'
      });
    }

    // Get current user's role
    const currentUserRole = await Role.findById(req.user.roleId);

    // Prevent creating root users through API
    if (targetRole.name === 'root') {
      return res.status(403).json({
        success: false,
        message: 'Cannot create root users through API'
      });
    }

    // Admin cannot create global scope users
    if (currentUserRole.scope === 'company' && targetRole.scope === 'global') {
      return res.status(403).json({
        success: false,
        message: 'Insufficient permissions to create global users'
      });
    }

    // Admin cannot create other admin users
    if (currentUserRole.name === 'admin' && targetRole.name === 'admin') {
      return res.status(403).json({
        success: false,
        message: 'Insufficient permissions to create admin users'
      });
    }

    // Admin can only create users for their companies
    if (currentUserRole.scope === "company" && companies?.length) {
      const invalidCompanies = companies.filter(
        (companyId) =>
          !req.user.companies.some(
            (userCompany) => userCompany._id.toString() === companyId.toString()
          )
      );

      if (invalidCompanies.length > 0) {
        return res.status(403).json({
          success: false,
          message: "Can only create users for your own companies",
        });
      }
    }

    const newUser = await User.create({
      email,
      password,
      firstName,
      lastName,
      phone,
      roleId,
      companies: companies || [],
      createdBy: req.user._id
    });

    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: req.user.companies?.[0] || null,
      action: 'create',
      module: 'users',
      entityType: 'User',
      entityId: newUser._id,
      description: `Created new user: ${newUser.email}`
    });

    const userData = await User.findById(newUser._id)
      .populate('roleId', 'name displayName')
      .populate('companies', 'name code')
      .populate('createdBy', 'firstName lastName email')
      .select('-password -refreshToken');

    res.status(201).json({
      success: true,
      message: 'User created successfully',
      data: userData
    });

  } catch (error) {
    next(error);
  }
};

exports.updateUser = async (req, res, next) => {
  try {
    const { id } = req.params;
    const updates = { ...req.body };

    delete updates.password;
    delete updates.refreshToken;

    const targetUser = await User.findById(id).populate("roleId");
    if (!targetUser) return res.status(404).json({ success: false, message: "User not found" });

    const currentUserRole = await Role.findById(req.user.roleId).select("name scope");

    if (targetUser.roleId?.name === "root" && currentUserRole.name !== "root")
      return res.status(403).json({ success: false, message: "Cannot update root users" });

    if (currentUserRole.scope === "company" && targetUser.roleId?.scope === "global")
      return res.status(403).json({ success: false, message: "Insufficient permissions to update global users" });

    // Admin cannot update other admin users
    if (currentUserRole.name === "admin" && targetUser.roleId?.name === "admin" && targetUser._id.toString() !== req.user._id.toString())
      return res.status(403).json({ success: false, message: "Access denied: Cannot update other admin users" });

    // ✅ Company scope checks
    // ✅ Company scope checks
if (currentUserRole.scope === "company") {
  const targetCompanies = targetUser.companies || [];

  // Check if target user is in admin's companies (existing user validation)
  const hasCommonCompany = targetCompanies.some(company =>
    req.user.companies.some(userCompany => {
      const userCompanyId = typeof userCompany === 'object' && userCompany._id 
        ? userCompany._id.toString() 
        : userCompany.toString();
      return userCompanyId === company.toString();
    })
  );

  if (!hasCommonCompany && targetCompanies.length > 0)
    return res.status(403).json({ success: false, message: "Can only update users in your companies" });

  // Validate new companies being assigned
  const updateCompanies = Array.isArray(updates.companies)
    ? updates.companies
    : updates.companies
      ? [updates.companies]
      : null;

  if (updateCompanies) {
    const invalidCompanies = updateCompanies.filter(
      (companyId) =>
        !req.user.companies.some((userCompany) => {
          const userCompanyId = typeof userCompany === 'object' && userCompany._id 
            ? userCompany._id.toString() 
            : userCompany.toString();
          return userCompanyId === companyId.toString();
        })
    );

    if (invalidCompanies.length)
      return res.status(403).json({ success: false, message: "Can only assign users to your own companies" });
  }
}

    // ✅ Role update checks
    if (updates.roleId) {
      const newRole = await Role.findById(updates.roleId).select("name scope");
      if (!newRole) return res.status(400).json({ success: false, message: "Invalid role" });

      if (newRole.name === "root")
        return res.status(403).json({ success: false, message: "Cannot assign root role through API" });

      if (currentUserRole.scope === "company" && newRole.scope === "global")
        return res.status(403).json({ success: false, message: "Cannot assign global roles" });
    }

    updates.updatedBy = req.user._id;

    const user = await User.findByIdAndUpdate(id, updates, { new: true, runValidators: true })
      .populate("roleId", "name displayName")
      .populate("companies", "name code")
      .populate("createdBy", "firstName lastName email")
      .populate("updatedBy", "firstName lastName email")
      .select("-password -refreshToken");

    await ActivityLog.create({
      userId: req.user._id,
      companyId: req.user.companies?.[0] || null,
      action: "update",
      module: "users",
      entityType: "User",
      entityId: user._id,
      description: `Updated user: ${user.email}`,
      changes: updates,
    });

    res.status(200).json({ success: true, message: "User updated successfully", data: user });
  } catch (error) {
    next(error);
  }
};

exports.updateUserStatus = async (req, res, next) => {
  try {
    const { id } = req.params;
    const { status } = req.body;

    if (!["active", "inactive", "suspended"].includes(status)) {
      return res.status(400).json({
        success: false,
        message: "Invalid status. Must be: active, inactive, or suspended",
      });
    }

    const targetUser = await User.findById(id).populate("roleId");
    if (!targetUser) return res.status(404).json({ success: false, message: "User not found" });

    const currentUserRole = await Role.findById(req.user.roleId).select("name scope");

    // Prevent updating root users unless current user is also root
    if (targetUser.roleId?.name === "root" && currentUserRole.name !== "root") {
      return res.status(403).json({ success: false, message: "Cannot update root users" });
    }

    // Admin cannot update global scope users
    if (currentUserRole.scope === "company" && targetUser.roleId?.scope === "global") {
      return res.status(403).json({ success: false, message: "Insufficient permissions to update global users" });
    }

    // Admin cannot update other admin users
    if (currentUserRole.name === "admin" && targetUser.roleId?.name === "admin" && targetUser._id.toString() !== req.user._id.toString()) {
      return res.status(403).json({ success: false, message: "Access denied: Cannot update other admin users" });
    }

    // Admin can only update users in their companies
    if (currentUserRole.scope === "company") {
      const hasCommonCompany = targetUser.companies.some(company =>
        req.user.companies.some(userCompany => {
          const userCompanyId = typeof userCompany === 'object' && userCompany._id 
            ? userCompany._id.toString() 
            : userCompany.toString();
          return userCompanyId === company.toString();
        })
      );

      if (!hasCommonCompany && targetUser.companies.length > 0)
        return res.status(403).json({ success: false, message: "Can only update users in your companies" });
    }

    const updatedUser = await User.findByIdAndUpdate(
      id,
      { status, updatedBy: req.user._id },
      { new: true, runValidators: true }
    )
      .populate("roleId", "name displayName")
      .populate("companies", "name code")
      .populate("createdBy", "firstName lastName email")
      .populate("updatedBy", "firstName lastName email")
      .select("-password -refreshToken");

    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: req.user.companies?.[0] || null,
      action: "update",
      module: "users",
      entityType: "User",
      entityId: updatedUser._id,
      description: `Updated user status: ${updatedUser.email} -> ${status}`,
      changes: { status },
      ipAddress: req.ip,
      userAgent: req.get("user-agent")
    });

    res.status(200).json({
      success: true,
      message: `User status updated to ${status}`,
      data: updatedUser,
    });
  } catch (error) {
    next(error);
  }
};


exports.deleteUser = async (req, res, next) => {
  try {
    const { id } = req.params;

    // Get the user to be deleted
    const targetUser = await User.findById(id).populate('roleId');
    if (!targetUser) {
      return res.status(404).json({
        success: false,
        message: 'User not found'
      });
    }

    // Get current user's role
    const currentUserRole = await Role.findById(req.user.roleId);

    // Prevent deleting root users
    if (targetUser.roleId.name === 'root') {
      return res.status(403).json({
        success: false,
        message: 'Cannot delete root users'
      });
    }

    // Prevent deleting yourself
    if (targetUser._id.toString() === req.user._id.toString()) {
      return res.status(403).json({
        success: false,
        message: 'Cannot delete your own account'
      });
    }

    // Admin cannot delete global scope users
    if (currentUserRole.scope === 'company' && targetUser.roleId.scope === 'global') {
      return res.status(403).json({
        success: false,
        message: 'Insufficient permissions to delete global users'
      });
    }

    // Admin cannot delete other admin users
    if (currentUserRole.name === 'admin' && targetUser.roleId.name === 'admin' && targetUser._id.toString() !== req.user._id.toString()) {
      return res.status(403).json({
        success: false,
        message: 'Access denied: Cannot delete other admin users'
      });
    }

    // Admin can only delete users in their companies
    if (currentUserRole.scope === 'company') {
      const hasCommonCompany = targetUser.companies.some(company =>
        req.user.companies.some(userCompany =>
          userCompany.toString() === company.toString()
        )
      );

      if (!hasCommonCompany && targetUser.companies.length > 0) {
        return res.status(403).json({
          success: false,
          message: 'Can only delete users in your companies'
        });
      }
    }

    await User.findByIdAndDelete(id);

    await ActivityLog.create({
      userId: req.user._id,
      companyId: req.user.companies?.[0] || null,
      action: 'delete',
      module: 'users',
      entityType: 'User',
      entityId: targetUser._id,
      description: `Deleted user: ${targetUser.email}`
    });

    res.status(200).json({
      success: true,
      message: 'User deleted successfully'
    });

  } catch (error) {
    next(error);
  }
};

exports.resetPassword = async (req, res, next) => {
  try {
    const { id } = req.params;
    const { password } = req.body;

    if (!password || password.length < 8) {
      return res.status(400).json({
        success: false,
        message: 'Password must be at least 8 characters'
      });
    }

    const targetUser = await User.findById(id).populate("roleId");
    if (!targetUser) return res.status(404).json({ success: false, message: "User not found" });

    const currentUserRole = await Role.findById(req.user.roleId).select("name scope");

    // Only root or super admin can reset passwords
    if (!['root', 'super_admin'].includes(currentUserRole.name)) {
      return res.status(403).json({
        success: false,
        message: 'Insufficient permissions to reset passwords'
      });
    }

    // Prevent resetting root users unless current user is also root
    if (targetUser.roleId?.name === "root" && currentUserRole.name !== "root") {
      return res.status(403).json({ success: false, message: "Cannot reset password for root users" });
    }

    // Update password
    targetUser.password = password;
    targetUser.updatedBy = req.user._id;
    await targetUser.save();

    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: req.user.companies?.[0] || null,
      action: "update",
      module: "users",
      entityType: "User",
      entityId: targetUser._id,
      description: `Reset password for user: ${targetUser.email}`,
    });

    res.status(200).json({
      success: true,
      message: "Password reset successfully",
    });
  } catch (error) {
    next(error);
  }
};