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

const generateToken = (userId) => {
  return jwt.sign({ userId }, process.env.JWT_SECRET, {
    expiresIn: process.env.JWT_EXPIRES_IN
  });
};

const generateRefreshToken = (userId) => {
  return jwt.sign({ userId }, process.env.JWT_REFRESH_SECRET, {
    expiresIn: process.env.JWT_REFRESH_EXPIRES_IN
  });
};

exports.login = async (req, res, next) => {
  try {
    const email = req.body.email?.trim().toLowerCase();
    const password = req.body.password?.trim();

    if (!email || !password)
      return res.status(400).json({ success: false, message: "Please provide email and password" });

    const user = await User.findOne({ email })
      .select("+password")
      .populate("companies", "name code")
      .populate("roleId");

    if (!user?.password || !(await user.comparePassword(password)))
      return res.status(401).json({ success: false, message: "Invalid email or password" });

    if (user.status !== "active")
      return res.status(403).json({ success: false, message: "Your account has been suspended." });

    const token = generateToken(user._id);
    const refreshToken = generateRefreshToken(user._id);

    user.refreshToken = refreshToken;
    user.lastLogin = new Date();
    await user.save({ validateBeforeSave: false });

    await ActivityLog.create({
      userId: user._id,
      companyId: user.companies?.[0]?._id || null,
      action: "login",
      module: "auth",
      description: "User logged in",
      ipAddress: req.ip,
      userAgent: req.get("user-agent")
    });

    const permissions = {};
    user.roleId?.modulePermissions?.forEach(mp => (permissions[mp.moduleName] = Object.fromEntries(mp.permissions)));

    res.json({
      success: true,
      message: "Login successful",
      data: {
        user: {
          id: user._id,
          email: user.email,
          firstName: user.firstName,
          lastName: user.lastName,
          fullName: `${user.firstName} ${user.lastName}`,
          phone: user.phone,
          avatar: user.avatar,
          role: user.roleId?.name,
          roleDisplayName: user.roleId?.displayName,
          roleScope: user.roleId?.scope,
          companies: user.companies?.map(c => ({ id: c._id, name: c.name, code: c.code })) || [],
          permissions,
          specialPermissions: user.roleId?.specialPermissions,
          lastLogin: user.lastLogin
        },
        token,
        refreshToken
      }
    });
  } catch (e) {
    next(e);
  }
};


// Keep other methods same...
exports.logout = async (req, res, next) => {
  try {
    await User.findByIdAndUpdate(req.user._id, { refreshToken: null });
    
    await ActivityLog.create({
      userId: req.user._id,
      companyId: req.user.companies?.[0]?._id || null,
      action: 'logout',
      module: 'auth',
      description: 'User logged out'
    });
    
    res.status(200).json({
      success: true,
      message: 'Logged out successfully'
    });
  } catch (error) {
    next(error);
  }
};

exports.getMe = async (req, res, next) => {
  try {
    const user = await User.findById(req.user._id)
      .populate('companies', 'name code')
      .populate('roleId')
      .populate('createdBy', 'firstName lastName email')
      .populate('updatedBy', 'firstName lastName email');
    
    const modulePermissions = {};
    user.roleId.modulePermissions.forEach(mp => {
      modulePermissions[mp.moduleName] = Object.fromEntries(mp.permissions);
    });
    
    res.status(200).json({
      success: true,
      data: {
        id: user._id,
        email: user.email,
        firstName: user.firstName,
        lastName: user.lastName,
        fullName: `${user.firstName} ${user.lastName}`,
        phone: user.phone,
        avatar: user.avatar,
        role: user.roleId.name,
        roleDisplayName: user.roleId.displayName,
        roleScope: user.roleId.scope,
        companies: user.companies?.map(c => ({
          id: c._id,
          name: c.name,
          code: c.code
        })) || [],
        createdBy: user.createdBy ? {
          id: user.createdBy._id,
          name: user.createdBy.fullName || `${user.createdBy.firstName} ${user.createdBy.lastName}`,
          email: user.createdBy.email
        } : null,
        updatedBy: user.updatedBy ? {
          id: user.updatedBy._id,
          name: user.updatedBy.fullName || `${user.updatedBy.firstName} ${user.updatedBy.lastName}`,
          email: user.updatedBy.email
        } : null,
        permissions: modulePermissions,
        specialPermissions: user.roleId.specialPermissions,
        lastLogin: user.lastLogin,
        status: user.status
      }
    });
  } catch (error) {
    next(error);
  }
};

exports.changePassword = async (req, res, next) => {
  try {
    const { currentPassword, newPassword } = req.body;

    if (!currentPassword || !newPassword) {
      return res.status(400).json({
        success: false,
        message: 'Please provide current and new password'
      });
    }

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

    const user = await User.findById(req.user._id).select('+password');

    if (!(await user.comparePassword(currentPassword))) {
      return res.status(401).json({
        success: false,
        message: 'Current password is incorrect'
      });
    }

    user.password = newPassword;
    await user.save();

    // Log activity
    await ActivityLog.create({
      userId: user._id,
      companyId: user.companies?.[0] || null,
      action: 'update',
      module: 'auth',
      description: 'User changed their own password'
    });

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