const User = require("../models/userModel");
const { errorResponse } = require("../utils/errorResponseHandler");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const { logUserAction } = require("../utils/userActionLogger");
require("../models/roleModel");
const Task = require("../models/taskModel");
const mongoose = require("mongoose");
const Role = require("../models/roleModel");
const { createNotification } = require("../services/notification.service");
// const Permission = require("../models/permissionModel");
const { pool } = require("../config/db");

// mongodb api
// const registerUser = async (req, res) => {
//   try {
//     const {
//       firstName,
//       lastName,
//       email,
//       password,
//       phone,
//       orgId,
//       gender,
//       department,
//       designation,
//       employeeId,
//       salary,
//       workingDays = 30,
//       // workingHours = 8,
//       employeeType = "full-time",
//       reportingManager,
//       // status,
//       address,
//       role,
//     } = req.body;

//     if (department && !mongoose.Types.ObjectId.isValid(department)) {
//       return errorResponse(res, "Invalid department", 400);
//     }

//     let profileImage = null;

//     if (req.file) {
//       profileImage = req.file.filename;
//     }
//     if (!firstName || !email || !password || !orgId) {
//       return errorResponse(
//         res,
//         "First name, email, password and organization ID are required",
//         400,
//       );
//     }

//     const existingUser = await User.findOne({ email });
//     if (existingUser) {
//       return errorResponse(res, "Email already in use", 400);
//     }

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

//     let parsedAddress = {};
//     if (address) {
//       try {
//         parsedAddress =
//           typeof address === "string" ? JSON.parse(address) : address;
//       } catch {
//         parsedAddress = {};
//       }
//     }

//     const workingHours = {
//       start: req.body.startTime || "09:30",
//       end: req.body.endTime || "18:30",
//     };

//     if (workingDays < 1 || workingDays > 31) {
//       return errorResponse(res, "Invalid working days", 400);
//     }

//     if (workingHours < 1 || workingHours > 24) {
//       return errorResponse(res, "Invalid working hours", 400);
//     }

//     const newUser = new User({
//       firstName,
//       lastName,
//       email,
//       password: hashedPassword,
//       phone,
//       role: role || "user",
//       // role: userRole._id,
//       orgId,
//       gender: gender || "other",
//       department: department || null,
//       designation: designation || null,
//       employeeId: employeeId || null,
//       // status: status !== undefined ? status : true,
//       salary,
//       workingDays: workingDays || 30,
//       workingHours,
//       // workingHours: workingHours || 8,
//       employeeType: employeeType || "full-time",
//       reportingManager: reportingManager || null,
//       // status,
//       address: parsedAddress,
//       profileImage, //  STORED

//     });

//     const savedUser = await newUser.save();

//     const token = jwt.sign(
//       { userId: savedUser._id, role: savedUser.role },
//       process.env.JWT_SECRET,
//       { expiresIn: "30d" },
//     );

//     await logUserAction({
//       userId: savedUser._id,
//       action: "REGISTER",
//       model: "User",
//       details: { email, firstName, lastName },
//       req,
//     });

//     return res.status(201).json({
//       success: true,
//       message: "User registered successfully",
//       data: {
//         user: savedUser,
//         token,
//       },
//     });
//   } catch (err) {
//     console.error("Register user error:", err);
//     return errorResponse(res, "Failed to register user", 500, err);
//   }
// };

// postgre sql api
const registerUser = async (req, res) => {
  const client = await pool.connect();

  try {
    const {
      firstName,
      lastName,
      email,
      password,
      phone,
      orgId,
      gender,
      department,
      designation,
      // employeeId,
      salary,
      workingDays = 30,
      employeeType = "full-time",
      reportingManager,
      address,
      role,
      startTime,
      endTime,
    } = req.body;

    /* ===== 1. VALIDATIONS ===== */

    if (!firstName || !email || !password || !orgId) {
      return res.status(400).json({
        success: false,
        message: "First name, email, password and organization ID are required",
      });
    }

    if (workingDays < 1 || workingDays > 31) {
      return res.status(400).json({
        success: false,
        message: "Invalid working days",
      });
    }

    /* ===== 2. CHECK EMAIL EXISTS ===== */

    const existingUser = await client.query(
      `SELECT id FROM users WHERE email = $1`,
      [email],
    );

    if (existingUser.rowCount > 0) {
      return res.status(400).json({
        success: false,
        message: "Email already in use",
      });
    }

    /* ===== 3. HASH PASSWORD ===== */

    const hashedPassword = await bcrypt.hash(password, 10);

    /* ===== 4. HANDLE FILE ===== */

    let profileImage = null;
    if (req.file) {
      profileImage = req.file.filename;
    }

    /* ===== 5. PARSE ADDRESS ===== */

    let parsedAddress = {};
    if (address) {
      try {
        parsedAddress =
          typeof address === "string" ? JSON.parse(address) : address;
      } catch {
        parsedAddress = {};
      }
    }

    /* ===== 6. WORKING HOURS ===== */

    const workingHours = {
      start: startTime || "09:30",
      end: endTime || "18:30",
    };

    /* ===== 7. INSERT USER ===== */

    const fullName = `${firstName} ${lastName || ""}`.trim();

    const insertQuery = `
      INSERT INTO users (
        name,
        first_name,
        last_name,
        email,
        password,
        phone,
        role,
        org_id,
        gender,
        department_id,
        designation_id,
        salary,
        working_days,
        working_hours,
        employee_type,
        reporting_manager,
        address,
        profile_image,
        created_at
      )
      VALUES (
        $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,
        $11,$12,$13,$14,$15,$16,$17,$18,NOW()
      )
      RETURNING *
    `;

    // const values = [
    //   firstName,
    //   lastName || null,
    //   email,
    //   hashedPassword,
    //   phone || null,
    //   role || "user",
    //   Number(orgId),
    //   department ? Number(department) : null, //  FIX
    //   designation ? Number(designation) : null, //  FIX
    //   gender || "other",
    //   salary || null,
    //   workingDays,
    //   JSON.stringify(workingHours), // JSONB
    //   employeeType,
    //   reportingManager || null,
    //   JSON.stringify(parsedAddress), // JSONB
    //   profileImage,
    // ];
    const values = [
      fullName,
      firstName,
      lastName || null,
      email,
      hashedPassword,
      phone || null,
      role || "user",
      Number(orgId),
      gender || "other",

      department ? Number(department) : null,
      designation ? Number(designation) : null,

      salary || null,
      workingDays,
      JSON.stringify(workingHours),
      employeeType,
      reportingManager || null,
      JSON.stringify(parsedAddress),
      profileImage,
    ];

    const result = await client.query(insertQuery, values);

    const savedUser = result.rows[0];

    /* ===== 8. GENERATE TOKEN ===== */

    const token = jwt.sign(
      { userId: savedUser.id, role: savedUser.role },
      process.env.JWT_SECRET,
      { expiresIn: "30d" },
    );

    /* ===== 9. LOG ACTION (OPTIONAL) ===== */

    await logUserAction({
      userId: savedUser.id,
      action: "REGISTER",
      model: "User",
      details: { email, firstName, lastName },
      req,
    });

    /* ===== 10. RESPONSE ===== */

    return res.status(201).json({
      success: true,
      message: "User registered successfully",
      data: {
        user: savedUser,
        token,
      },
    });
  } catch (err) {
    console.error("Register user error:", err);

    return res.status(500).json({
      success: false,
      message: "Failed to register user",
    });
  } finally {
    client.release();
  }
};

const loginUser = async (req, res) => {
  const client = await pool.connect();
  
  try {
    const { email, password } = req.body;

    /* ===== 1. VALIDATION ===== */
    if (!email || !password) {
      return errorResponse(res, "Email and password are required", 400);
    }

    /* ===== 2. GET USER ===== */
    const userQuery = `
      SELECT * FROM users WHERE email = $1 LIMIT 1
    `;
    const userResult = await client.query(userQuery, [email]);

    if (userResult.rowCount === 0) {
      return errorResponse(res, "Invalid email or password", 401);
    }

    const user = userResult.rows[0];

    /* ===== 3. CHECK PASSWORD ===== */
    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) {
      return errorResponse(res, "Invalid email or password", 401);
    }

    /* ===== 4. UPDATE LOGIN META ===== */
    const updateQuery = `
      UPDATE users
      SET 
        last_login = NOW(),
        device_id = COALESCE($1, device_id),
        device_model = COALESCE($2, device_model),
        app_version = COALESCE($3, app_version),
        device_token = COALESCE($4, device_token)
      WHERE id = $5
    `;

    await client.query(updateQuery, [
      req.headers["x-device-id"] || null,
      req.headers["x-device-model"] || req.headers["user-agent"] || null,
      req.headers["x-app-version"] || "Browser",
      req.headers["x-device-token"] || null,
      user.id,
    ]);

    /* ===== 5. GENERATE TOKEN ===== */
    const token = jwt.sign(
      { userId: user.id, role: user.role },
      process.env.JWT_SECRET,
      { expiresIn: "30d" },
    );

    /* ===== 6. FETCH COMPLETE PERMISSIONS FROM role_permissions TABLE ===== */
    const role = user.role?.toLowerCase().trim();

    // First, get the role_id from roles table
    const roleQuery = `
      SELECT id FROM roles WHERE LOWER(role_name) = LOWER($1) AND is_deleted = false LIMIT 1
    `;
    const roleResult = await client.query(roleQuery, [role]);

    let permissions = [];
    
    if (roleResult.rowCount > 0) {
      const roleId = roleResult.rows[0].id;
      
      // Fetch permissions from role_permissions table
      const permQuery = `
        SELECT * FROM role_permissions WHERE role_id = $1 AND is_deleted = false LIMIT 1
      `;
      const permResult = await client.query(permQuery, [roleId]);
      
      if (permResult.rowCount > 0) {
        const row = permResult.rows[0];
        
        // Convert flat row to array of permission objects with ALL actions
        const flatPermissions = [];
        const SKIP_COLUMNS = new Set([
          'id', 'role_id', 'org_id', 'created_by', 'updated_by',
          'is_deleted', 'created_at', 'updated_at'
        ]);
        
        // Track processed modules to avoid duplicates
        const processedModules = new Set();
        
        // First, identify all unique modules from columns
        for (const [columnName, value] of Object.entries(row)) {
          if (SKIP_COLUMNS.has(columnName)) continue;
          if (typeof value !== 'boolean') continue;
          
          // Get base module name (remove suffix)
          let moduleName = columnName;
          const suffixes = ['_view', '_add', '_edit', '_delete', '_download', '_approve'];
          
          for (const suffix of suffixes) {
            if (columnName.endsWith(suffix)) {
              moduleName = columnName.replace(suffix, '');
              break;
            }
          }
          
          if (!processedModules.has(moduleName)) {
            processedModules.add(moduleName);
            
            // Build complete permission object for this module
            const permissionObj = { module: moduleName };
            
            // Add view permission (from bare column OR _view column)
            if (row[moduleName] !== undefined) {
              permissionObj.view = row[moduleName] === true;
            } else if (row[`${moduleName}_view`] !== undefined) {
              permissionObj.view = row[`${moduleName}_view`] === true;
            } else {
              permissionObj.view = false;
            }
            
            // Add action permissions
            permissionObj.add = row[`${moduleName}_add`] === true || false;
            permissionObj.edit = row[`${moduleName}_edit`] === true || false;
            permissionObj.delete = row[`${moduleName}_delete`] === true || false;
            permissionObj.download = row[`${moduleName}_download`] === true || false;
            permissionObj.approve = row[`${moduleName}_approve`] === true || false;
            
            flatPermissions.push(permissionObj);
          }
        }
        
        permissions = flatPermissions;
        console.log(`✅ Loaded ${permissions.length} modules with full permissions for role ${role}`);
        console.log(`📋 Sample permission:`, permissions[0]);
      }
    }

    /* ===== 7. FORMAT USER ===== */
    const formattedUser = {
      id: user.id,
      fullName: user.name,
      firstName: user.first_name,
      lastName: user.last_name,
      email: user.email,
      phone: user.phone,
      role: user.role,
      orgId: user.org_id,
      departmentId: user.department_id,
      department: user.department_name,
    };

    /* ===== 8. SESSION ===== */
    req.session.user = {
      id: user.id,
      role: user.role,
      orgId: user.org_id,
      permissions, // Now includes full permissions
    };
    console.log("req.session.user: ",req.session.user);
    /* ===== 9. SAVE SESSION ===== */
    req.session.save(async (err) => {
      if (err) {
        console.error("Session save error:", err);
        return res.status(500).json({ message: "Session error" });
      }

      /* ===== 10. AUDIT LOG ===== */
      await logUserAction({
        action: "LOGIN",
        model: "User",
        details: { email },
        req,
      });

      /* ===== 11. NOTIFICATION (NON-BLOCKING) ===== */
      createNotification({
        orgId: user.org_id || null,
        title: "Welcome Back 👋",
        message: `Welcome back ${user.name || user.email}!`,
        type: "LOGIN",
        metadata: { loginAt: new Date() },
      }).catch((err) =>
        console.error("Login notification failed:", err.message),
      );

      /* ===== 12. RESPONSE ===== */
      return res.json({
        success: true,
        message: "Login successful",
        user: formattedUser,
        permissions, // Now includes full permissions
        token,
      });
    });
  } catch (err) {
    console.error("Login error:", err);
    return errorResponse(res, "Failed to login", 500);
  } finally {
    client.release();
  }
};

const validateToken = async (req, res) => {
  try {
    let token = req.headers.authorization;
    if (token && token.startsWith("Bearer ")) {
      token = token.split(" ")[1];
    }
    if (!token) return errorResponse(res, "No token provided", 401);

    let decoded;
    try {
      decoded = jwt.verify(token, process.env.JWT_SECRET);
    } catch (err) {
      return errorResponse(res, "Invalid or expired token", 401);
    }

    const user = await User.findById(decoded.userId).select("-password");
    if (!user) return errorResponse(res, "User not found", 404);

    // Optional: Log token validation
    await logUserAction({
      userId: user._id,
      action: "VALIDATE_TOKEN",
      model: "User",
      details: { tokenValid: true },
      req,
    });

    return res.json({
      success: true,
      message: "Token is valid",
      user,
    });
  } catch (err) {
    return errorResponse(res, "Failed to validate token", 500, err);
  }
};

// ------------------ GET ALL USERS ------------------
// mongodb
// const getAllUsers = async (req, res) => {
//   try {
//     let { page = 1, limit = 10 } = req.query;
//     page = parseInt(page);
//     limit = parseInt(limit);
//     const skip = (page - 1) * limit;

//     const [users, total] = await Promise.all([
//       // User.find({ isDeleted: false }) .populate("role", "name permissions").select("-password").skip(skip).limit(limit).sort({ createdAt: -1 }),
//       User.find({ isDeleted: false })
//         .populate("branch", "branchName address.city status")
//         .populate("createdBy", "firstName lastName role")
//         .populate("updatedBy", "firstName lastName role")
//         .sort({ createdAt: -1 })
//         .populate("department", "deptName status")
//         .populate("designation", "designationName status")
//         .populate("reportingManager", "firstName lastName role")
//         .populate("shift", "shiftName startTime endTime")
//         .select("-password")
//         .skip(skip)
//         .limit(limit)
//         .sort({ createdAt: -1 }),

//       User.countDocuments({ isDeleted: false }),
//     ]);
//     // console.log("REQ.USER IN getAllUsers:", req.user);

//     await logUserAction({
//       userId: req.user?._id,
//       // userId: req.user.id,
//       action: "READ",
//       model: "User",
//       details: { page, limit, count: users.length },
//       req,
//     });

//     return res.json({
//       success: true,
//       total,
//       page,
//       totalPages: Math.ceil(total / limit),
//       data: users,
//     });
//   } catch (err) {
//     return errorResponse(res, "Failed to fetch users", 500, err);
//   }
// };

// postgre sql
const getAllUsers = async (req, res) => {
  const client = await pool.connect();

  try {
    let { page = 1, limit = 10 } = req.query;
    page = parseInt(page);
    limit = parseInt(limit);
    const offset = (page - 1) * limit;

    /* ===== 1. GET USERS ===== */
    const usersQuery = `
      SELECT 
        u.id,
        u.first_name AS "firstName",
        u.last_name AS "lastName",
        u.email,
        u.phone,
        u.gender,
        u.role,
        u.status,
        u.created_at,

        -- Optional joins (safe)
        d.dept_name AS "departmentName",
        des.designation_name AS "designationName",
        rm.first_name AS "rmFirstName",
        rm.last_name AS "rmLastName"

      FROM users u

      LEFT JOIN departments d ON u.department_id = d.id
      LEFT JOIN designations des ON u.designation_id = des.id
      LEFT JOIN users rm ON u.reporting_manager = rm.id

      WHERE u.is_deleted = false

      ORDER BY u.created_at DESC
      LIMIT $1 OFFSET $2
    `;

    const countQuery = `
      SELECT COUNT(*) FROM users WHERE is_deleted = false
    `;

    const [usersResult, countResult] = await Promise.all([
      client.query(usersQuery, [limit, offset]),
      client.query(countQuery),
    ]);

    const users = usersResult.rows;
    const total = parseInt(countResult.rows[0].count);

    /* ===== 2. FORMAT RESPONSE (MATCH FRONTEND) ===== */
    const formattedUsers = users.map((user) => ({
      id: user.id, // keep same as Mongo for frontend
      firstName: user.firstName,
      lastName: user.lastName,
      email: user.email,
      phone: user.phone,
      gender: user.gender,
      role: user.role,
      status: user.status,

      designation: user.designationName
        ? { designationName: user.designationName }
        : null,

      department: user.departmentName
        ? { deptName: user.departmentName }
        : null,

      reportingManager:
        user.rmFirstName || user.rmLastName
          ? {
              firstName: user.rmFirstName,
              lastName: user.rmLastName,
            }
          : null,
    }));

    /* ===== 3. LOG ===== */
    await logUserAction({
      userId: req.user?.id,
      action: "READ",
      model: "User",
      details: { page, limit, count: users.length },
      req,
    });

    /* ===== 4. RESPONSE ===== */
    return res.json({
      success: true,
      total,
      page,
      totalPages: Math.ceil(total / limit),
      data: formattedUsers,
    });
  } catch (err) {
    console.error("GET USERS ERROR:", err);
    return errorResponse(res, "Failed to fetch users", 500);
  } finally {
    client.release();
  }
};

// ------------------ GET USER BY ID ------------------
// const getUserById = async (req, res) => {
//   try {
//     const user = await User.findById(req.params.id)
//       .populate("branch", "branchName address.city")
//       .populate("shift", "shiftName startTime endTime");
//     // .select("-password");
//     if (!user) return errorResponse(res, "User not found", 404);

//     await logUserAction({
//       // userId : req.user?.id,
//       userId: req.user?.id,
//       action: "READ",
//       model: "User",
//       details: { userId: user._id },
//       req,
//     });

//     return res.json(user);
//   } catch (err) {
//     return errorResponse(res, "Failed to fetch user", 500, err);
//   }
// };

const getUserById = async (req, res) => {
  const client = await pool.connect();

  try {
    const userId = req.params.id;

    /* ===== 1. FETCH USER ===== */
    const query = `
    SELECT
  u.id AS "id",
  COALESCE(u.first_name, '') AS "firstName",
  COALESCE(u.last_name, '') AS "lastName",
  u.email,
  COALESCE(u.phone, '') AS "phone",
  COALESCE(u.gender, 'other') AS "gender",
  u.role,
  u.status,

  u.father_name AS "fatherName",
  u.date_of_birth AS "dateOfBirth",
  u.aadhar_number AS "aadharNumber",
  u.pan_number AS "panNumber",
  u.marital_status AS "maritalStatus",
  u.blood_group AS "bloodGroup",
  u.emergency_contact AS "emergencyContact",
  u.id_proof_type AS "idProofType",

  u.address AS "address",

  u.org_id AS "orgId",
  u.department_id AS "department",
  u.designation_id AS "designation",
  u.reporting_manager AS "reportingManager",

  u.created_at AS "createdAt",
  u.updated_at AS "updatedAt"

FROM users u
WHERE u.id = $1 AND u.is_deleted = false
LIMIT 1
    `;

    const result = await client.query(query, [userId]);

    if (result.rowCount === 0) {
      return errorResponse(res, "User not found", 404);
    }

    const user = result.rows[0];

    if (user.address) {
      user.address =
        typeof user.address === "string"
          ? JSON.parse(user.address)
          : user.address;
    }

    /* ===== 2. LOG ACTION ===== */
    await logUserAction({
      userId: req.user?.id,
      action: "READ",
      model: "User",
      details: { userId: user._id },
      req,
    });

    /* ===== 3. RESPONSE ===== */
    return res.json({
      success: true,
      data: user,
    });
  } catch (err) {
    console.error("Get user error:", err);
    return errorResponse(res, "Failed to fetch user", 500);
  } finally {
    client.release();
  }
};

// ------------------ UPDATE USER ------------------
// const updateUser = async (req, res) => {
//   try {
//     const updates = { ...req.body, updatedBy: req.user?._id || null };
//     const user = await User.findByIdAndUpdate(req.params.id, updates, {
//       new: true,
//     });
//     if (!user) return errorResponse(res, "User not found", 404);

//     await logUserAction({
//       userId: req.user?._id,
//       action: "UPDATE",
//       model: "User",
//       details: { userId: user._id, updates },
//       req,
//     });

//     return res.json({
//       success: true,
//       message: "User updated successfully",
//       data: user,
//     });
//   } catch (err) {
//     return errorResponse(res, "Failed to update user", 500, err);
//   }
// };

const updateUser = async (req, res) => {
  const client = await pool.connect();

  try {
    const userId = req.params.id;
    const updates = req.body;

    /* ===== 1. BUILD DYNAMIC UPDATE QUERY ===== */
    const fields = [];
    const values = [];
    let index = 1;

    // Map allowed fields (prevent unwanted updates)
    const allowedFields = {
      firstName: "first_name",
      lastName: "last_name",
      email: "email",
      phone: "phone",
      gender: "gender",
      role: "role",
      status: "status",

      fatherName: "father_name",
      dob: "date_of_birth",
      aadharNumber: "aadhar_number",
      panNumber: "pan_number",
      maritalStatus: "marital_status",
      bloodGroup: "blood_group",
      emergencyContact: "emergency_contact",
      idProof: "id_proof_type",

      orgId: "org_id",
      department: "department_id",
      designation: "designation_id",
      reportingManager: "reporting_manager",
    };

    for (const key in updates) {
      // if (allowedFields[key]) {
      //   fields.push(`${allowedFields[key]} = $${index}`);
      //   values.push(updates[key]);
      //   index++;
      // }
      if (key === "address") {
        fields.push(`address = $${index}`);
        values.push(JSON.stringify(updates.address)); // JSONB
        index++;
      } else if (allowedFields[key]) {
        fields.push(`${allowedFields[key]} = $${index}`);
        values.push(updates[key]);
        index++;
      }
    }

    // always update updated_by + updated_at
    fields.push(`updated_by = $${index}`);
    values.push(req.user?.id || null);
    index++;

    fields.push(`updated_at = NOW()`);

    if (fields.length === 0) {
      return errorResponse(res, "No valid fields to update", 400);
    }

    /* ===== 2. EXECUTE UPDATE ===== */
    const query = `
      UPDATE users
      SET ${fields.join(", ")}
      WHERE id = $${index}
      RETURNING *
    `;
    values.push(userId);

    const result = await client.query(query, values);

    if (result.rowCount === 0) {
      return errorResponse(res, "User not found", 404);
    }

    // const user = result.rows[0];
    const userRes = await client.query(
      `
  SELECT 
    u.*,

    json_build_object(
      'id', d.id,
      'deptName', d.dept_name
    ) AS department,

    json_build_object(
      'id', des.id,
      'designationName', des.designation_name
    ) AS designation,

    json_build_object(
      'id', org.id,
      'orgName', org.org_name
    ) AS org

  FROM users u
  LEFT JOIN departments d ON u.department_id = d.id
  LEFT JOIN designations des ON u.designation_id = des.id
  LEFT JOIN organizations org ON u.org_id = org.id

  WHERE u.id = $1
  `,
      [userId],
    );

    const user = userRes.rows[0];

    /* ===== 3. LOG ACTION ===== */
    await logUserAction({
      userId: req.user?.id,
      action: "UPDATE",
      model: "User",
      details: { userId: user.id, updates },
      req,
    });

    /* ===== 4. RESPONSE ===== */
    return res.json({
      success: true,
      message: "User updated successfully",
      data: user,
    });
  } catch (err) {
    console.error("Update user error:", err);
    return errorResponse(res, "Failed to update user", 500);
  } finally {
    client.release();
  }
};

// delete user controller
// const deleteUser = async (req, res) => {
//   try {
//     const user = await User.findByIdAndUpdate(
//       req.params.id,
//       { isDeleted: true },
//       { new: true },
//     );
//     if (!user) return errorResponse(res, "User not found", 404);

//     // log action
//     await logUserAction({
//       userId: req.user?._id,
//       orgId: user.orgId || null,
//       action: "DELETE",
//       model: "User",
//       details: { userId: user._id },
//       req,
//     });

//     return res.json({
//       success: true,
//       message: "User deleted successfully",
//     });
//   } catch (err) {
//     return errorResponse(res, "Failed to delete user", 500, err);
//   }
// };

const deleteUser = async (req, res) => {
  const client = await pool.connect();

  try {
    const userId = req.params.id;

    /* ===== 1. SOFT DELETE ===== */
    const updateQuery = `
      UPDATE users
      SET is_deleted = true,
          updated_at = NOW()
      WHERE id = $1
      RETURNING *
    `;

    const result = await client.query(updateQuery, [userId]);

    if (result.rowCount === 0) {
      return errorResponse(res, "User not found", 404);
    }

    const user = result.rows[0];

    /* ===== 2. LOG ACTION ===== */
    await logUserAction({
      userId: req.user?.id, // PostgreSQL uses id (not _id)
      orgId: user.org_id || null,
      action: "DELETE",
      model: "User",
      details: { userId: user.id },
      req,
    });

    /* ===== 3. RESPONSE ===== */
    return res.json({
      success: true,
      message: "User deleted successfully",
    });
  } catch (err) {
    console.error("Delete user error:", err);
    return errorResponse(res, "Failed to delete user", 500);
  } finally {
    client.release();
  }
};

// ------------------ DEACTIVATE USER ------------------
const deactivateUser = async (req, res) => {
  try {
    const user = await User.findByIdAndUpdate(
      req.params.id,
      { status: false },
      { new: true },
    );
    if (!user) return errorResponse(res, "User not found", 404);

    await logUserAction({
      userId: req.user?._id,
      action: "DEACTIVATE",
      model: "User",
      details: { userId: user._id },
      req,
    });

    return res.json({
      success: true,
      message: "User deactivated successfully",
      data: user,
    });
  } catch (err) {
    return errorResponse(res, "Failed to deactivate user", 500, err);
  }
};

// ------------------ LOGOUT FROM DEVICE ------------------
// const logoutFromDevice = async (req, res) => {
//   try {
//     const { userId, deviceId } = req.body;
//     if (!userId || !deviceId)
//       return errorResponse(res, "userId and deviceId are required", 400);

//     const user = await User.findById(userId);
//     if (!user) return errorResponse(res, "User not found", 404);

//     if (user.deviceId === deviceId) {
//       user.deviceId = null;
//       user.deviceToken = null;
//       user.playerId = null;
//       await user.save();
//     }

//     await logUserAction({
//       userId,
//       action: "LOGOUT",
//       model: "User",
//       details: { deviceId },
//       req,
//     });

//     return res.json({
//       success: true,
//       message: "Logged out from device successfully",
//       data: user,
//     });
//   } catch (err) {
//     return errorResponse(res, "Failed to logout from device", 500, err);
//   }
// };

const logoutFromDevice = async (req, res) => {
  const client = await pool.connect();

  try {
    const { userId, deviceId } = req.body;

    //  Validation
    if (!userId || !deviceId) {
      return errorResponse(res, "userId and deviceId are required", 400);
    }

    const parsedUserId = parseInt(userId, 10);

    if (!parsedUserId || isNaN(parsedUserId)) {
      return errorResponse(res, "Invalid user ID", 400);
    }

    await client.query("BEGIN");

    //  Check user exists
    const userRes = await client.query(
      `SELECT id, device_id FROM users WHERE id = $1`,
      [parsedUserId],
    );

    if (userRes.rowCount === 0) {
      await client.query("ROLLBACK");
      return errorResponse(res, "User not found", 404);
    }

    const user = userRes.rows[0];

    //  Only logout if device matches
    let updatedUser = user;

    if (user.device_id === deviceId) {
      const updateRes = await client.query(
        `
        UPDATE users
        SET device_id = NULL,
            device_token = NULL,
            player_id = NULL,
            updated_at = NOW()
        WHERE id = $1
        RETURNING *;
        `,
        [parsedUserId],
      );

      updatedUser = updateRes.rows[0];
    }

    //  Log action
    await logUserAction({
      userId: parsedUserId,
      action: "LOGOUT",
      model: "User",
      details: { deviceId },
      req,
    });

    await client.query("COMMIT");

    return res.json({
      success: true,
      message: "Logged out from device successfully",
      data: updatedUser,
    });
  } catch (err) {
    await client.query("ROLLBACK");
    return errorResponse(res, "Failed to logout from device", 500, err);
  } finally {
    client.release();
  }
};

// ------------------ PROFILE IMAGE UPLOAD ------------------
const profileImageUpload = async (req, res) => {
  try {
    if (!req.file) {
      return errorResponse(res, "No file uploaded", 400);
    }

    const user = await User.findById(req.params.id);
    if (!user) {
      return errorResponse(res, "User not found", 404);
    }

    // ✅ Convert Windows path → web path
    const imagePath = `/uploads/images/${req.file.filename}`;

    user.profileImage = imagePath;
    await user.save();

    await logUserAction({
      userId: req.user?._id,
      action: "UPLOAD_PROFILE_IMAGE",
      model: "User",
      details: {
        userId: user._id,
        filePath: imagePath,
      },
      req,
    });

    return res.json({
      success: true,
      message: "Profile image uploaded successfully",
      data: {
        _id: user._id,
        profileImage: imagePath,
      },
    });
  } catch (err) {
    console.error("Profile image upload error:", err);
    return errorResponse(res, "Failed to upload profile image", 500, err);
  }
};

// ------------------ FORGOT PASSWORD ------------------
const forgotPassword = async (req, res) => {
  try {
    const { email, newPassword } = req.body;
    if (!email || !newPassword)
      return errorResponse(res, "Email and new password are required", 400);

    const user = await User.findOne({ email });
    if (!user) return errorResponse(res, "User not found", 404);

    user.password = await bcrypt.hash(newPassword, 10);
    await user.save();

    await logUserAction({
      userId: user._id,
      action: "RESET_PASSWORD",
      model: "User",
      details: { email },
      req,
    });

    return res.json({
      success: true,
      message: "Password reset successfully",
    });
  } catch (err) {
    return errorResponse(res, "Failed to reset password", 500, err);
  }
};

const changePassword = async (req, res) => {
  try {
    const userId = req.user._id;
    const { currentPassword, newPassword, confirmPassword } = req.body;
    console.log(currentPassword);
    console.log(newPassword);

    if (!currentPassword || !newPassword || !confirmPassword) {
      return errorResponse(
        res,
        "Current password, new password and confirm password are required",
        400,
      );
    }

    if (newPassword !== confirmPassword) {
      return errorResponse(res, "Passwords do not match", 400);
    }

    const user = await User.findById(userId).select("+password");
    if (!user) {
      return errorResponse(res, "User not found", 404);
    }

    //  IMPORTANT: await compare
    const isMatch = await bcrypt.compare(currentPassword, user.password);
    if (!isMatch) {
      return errorResponse(res, "Current password is incorrect", 400);
    }

    user.password = await bcrypt.hash(newPassword, 10);
    user.updatedAt = new Date();
    await user.save();

    //  audit log (same pattern as forgotPassword)
    await logUserAction({
      userId: user._id,
      action: "CHANGE_PASSWORD",
      model: "User",
      details: { userId: user._id },
      req,
    });

    return res.status(200).json({
      success: true,
      message: "Password changed successfully",
    });
  } catch (err) {
    return errorResponse(res, "Failed to change password", 500, err);
  }
};

// validate status update status
const updateUserStatus = async (req, res) => {
  try {
    const { status } = req.body;
    const userId = req.params.id;

    // ✅ Validate status
    if (!["Approved", "Rejected"].includes(status)) {
      return errorResponse(res, "Invalid status value", 400);
    }

    const user = await User.findById(userId);
    if (!user) {
      return errorResponse(res, "User not found", 404);
    }

    // ❌ Prevent re-approval
    if (user.status !== "Pending") {
      return errorResponse(res, `User already ${user.status}`, 400);
    }

    // ✅ Update status
    user.status = status;
    user.updatedBy = req.user._id;

    await user.save();

    // ✅ Audit log
    await logUserAction({
      userId: req.user._id,
      action: status === "Approved" ? "APPROVE_USER" : "REJECT_USER",
      model: "User",
      details: {
        targetUserId: user._id,
        status,
      },
      req,
    });

    return res.json({
      success: true,
      message: `User ${status.toLowerCase()} successfully`,
      data: {
        id: user._id,
        status: user.status,
      },
    });
  } catch (err) {
    console.error("Update user status error:", err);
    return errorResponse(res, "Failed to update user status", 500, err);
  }
};

// fetchAgents controller
// const getAgents = async (req, res) => {
//   try {
//     const orgId = req.user?.orgId;
//     console.log(orgId);

//     const userId = req.user?._id;

//     if (!orgId) {
//       return errorResponse(res, "Organization context missing", 400);
//     }

//     const agents = await User.find({
//       role: "agent",
//       status: "Approved",
//       isDeleted: false,
//       orgId,
//     })
//       .select("_id firstName lastName phone email branch shift")
//       .populate("branch", "branchName")
//       .populate("shift", "shiftName startTime endTime")
//       .lean();

//     // console.log(agents);

//     // Audit log
//     await logUserAction({
//       userId,
//       orgId,
//       action: "READ",
//       model: "User",
//       details: { fetched: "agents", count: agents.length },
//       req,
//     });

//     return res.status(200).json({
//       success: true,
//       message: "Agents fetched successfully",
//       data: agents,
//     });
//   } catch (error) {
//     return errorResponse(res, "Failed to fetch agents", 500, error);
//   }
// };

// mobile api's

const sendAgentOtp = async (req, res) => {
  try {
    const { phone } = req.body;
    if (!phone) {
      return errorResponse(res, "Phone number required", 400);
    }

    const user = await User.findOne({
      phone,
      role: "agent",
      status: "Approved",
      isDeleted: false,
    });

    if (!user) {
      return errorResponse(res, "Agent not found or not approved", 404);
    }

    const otp = Math.floor(100000 + Math.random() * 900000).toString();

    // await Otp.create({
    //   phone,
    //   otp: hashedOtp,
    //   expiresAt: new Date(Date.now() + 5 * 60 * 1000), // 5 min
    // });
    user.otp = otp;
    user.otpExpiresAt = new Date(Date.now() + 5 * 60 * 1000);
    await user.save();

    // ✅ clear old OTPs
    // await Otp.deleteMany({ phone });  future ref
    //  SMS integration later
    console.log("AGENT OTP:", otp);

    return res.json({
      success: true,
      message: "OTP sent successfully",
      data: otp,
    });
  } catch (err) {
    return errorResponse(res, "Failed to send OTP", 500, err);
  }
};

// const verifyAgentOtp = async (req, res) => {
//   try {
//     const { phone, otp, deviceId, appVersion } = req.body;

//     if (!phone || !otp) {
//       return errorResponse(res, "Phone and OTP required", 400);
//     }

//     // const otpDoc = await Otp.findOne({ phone, otp });
//     // if (!otpDoc) {
//     //   return errorResponse(res, "Invalid or expired OTP", 401);
//     // }

//     // if (otpDoc.expiresAt < new Date()) {
//     //   await Otp.deleteMany({ phone });
//     //   return errorResponse(res, "OTP expired", 401);
//     // }
//     // const isValidOtp = await bcrypt.compare(otp, otpDoc.otp);
//     // if (!isValidOtp) {
//     //   return errorResponse(res, "Invalid OTP", 401);
//     // }

//     const user = await User.findOne({
//       phone,
//       role: "agent",
//       status: "Approved",
//       isDeleted: false,
//     });

//     if (!user) {
//       return errorResponse(res, "Agent not found", 404);
//     }

//     // Update login metadata
//     user.lastLogin = new Date();
//     user.deviceId = deviceId || user.deviceId;
//     user.appVersion = appVersion || user.appVersion;

//     await user.save();
//     await Otp.deleteMany({ phone }); // cleanup

//     const token = jwt.sign(
//       { userId: user._id, role: user.role },
//       process.env.JWT_SECRET,
//       { expiresIn: "30d" }
//     );

//     await logUserAction({
//       userId: user._id,
//       action: "LOGIN_OTP",
//       model: "User",
//       details: { phone },
//       req,
//     });

//     return res.json({
//       success: true,
//       message: "OTP verified successfully",
//       data: {
//         user,
//         token,
//       },
//     });
//   } catch (err) {
//     return errorResponse(res, "OTP verification failed", 500, err);
//   }
// };
// const verifyAgentOtp = async (req, res) => {
//   try {
//     const { phone, otp, deviceId, appVersion } = req.body;

//     if (!phone || !otp) {
//       return errorResponse(res, "Phone and OTP required", 400);
//     }

//     // const otpDoc = await Otp.findOne({ phone });
//     const otpDoc = await Otp.findOne({ phone })
//       .sort({ createdAt: -1 });

//     if (!otpDoc) {
//       return errorResponse(res, "Invalid or expired OTP", 401);
//     }

//     if (otpDoc.expiresAt < new Date()) {
//       await Otp.deleteMany({ phone });
//       return errorResponse(res, "OTP expired", 401);
//     }

//     const isValidOtp = await bcrypt.compare(otp, otpDoc.otp);
//     if (!isValidOtp) {
//       return errorResponse(res, "Invalid OTP", 401);
//     }

//     const user = await User.findOne({
//       phone,
//       role: "agent",
//       status: "Approved",
//       isDeleted: false,
//     });

//     if (!user) {
//       return errorResponse(res, "Agent not found or not approved", 404);
//     }

//     // Update login metadata
//     user.lastLogin = new Date();
//     user.deviceId = deviceId || user.deviceId;
//     user.appVersion = appVersion || user.appVersion;
//     await user.save();

//     // Cleanup OTPs
//     await Otp.deleteMany({ phone });

//     // Generate JWT
//     const token = jwt.sign(
//       { userId: user._id, role: user.role },
//       process.env.JWT_SECRET,
//       { expiresIn: "30d" }
//     );

//     await logUserAction({
//       userId: user._id,
//       action: "LOGIN_OTP",
//       model: "User",
//       details: { phone },
//       req,
//     });

//     return res.status(200).json({
//       success: true,
//       message: "OTP verified successfully",
//       data: {
//         user,
//         token,
//       },
//     });
//   } catch (err) {
//     console.error("VERIFY OTP ERROR:", err);
//     return errorResponse(res, "OTP verification failed", 500, err);
//   }
// };

const verifyAgentOtp = async (req, res) => {
  try {
    const { phone, otp, deviceId, appVersion, deviceToken } = req.body;

    if (!phone || !otp) {
      return errorResponse(res, "Phone and OTP required", 400);
    }

    const user = await User.findOne({
      phone,
      role: "agent",
      status: "Approved",
      isDeleted: false,
    });

    if (!user || !user.otp) {
      return errorResponse(res, "Invalid or expired OTP", 401);
    }

    // if (user.otpExpiresAt < new Date()) {
    //   user.otp = null;
    //   user.otpExpiresAt = null;
    //   await user.save();
    //   return errorResponse(res, "OTP expired", 401);
    // }

    if (user.otp !== otp) {
      return errorResponse(res, "Invalid OTP", 401);
    }

    // OTP verified → cleanup
    user.otp = null;
    user.otpExpiresAt = null;
    user.lastLogin = new Date();
    user.deviceId = deviceId || user.deviceId;
    user.deviceToken = deviceToken || user.deviceToken;
    user.appVersion = appVersion || user.appVersion;
    await user.save();

    const token = jwt.sign(
      { userId: user._id, role: user.role },
      process.env.JWT_SECRET,
      // { expiresIn: "30d" }
    );

    await logUserAction({
      userId: user._id,
      action: "LOGIN_OTP",
      model: "User",
      details: { phone },
      req,
    });

    return res.status(200).json({
      success: true,
      message: "OTP verified successfully",
      data: { user, token },
    });
  } catch (err) {
    console.error("VERIFY OTP ERROR:", err);
    return errorResponse(res, "OTP verification failed", 500, err);
  }
};

const resendAgentOtp = async (req, res) => {
  try {
    const { phone } = req.body;
    if (!phone) {
      return errorResponse(res, "Phone number required", 400);
    }

    const user = await User.findOne({
      phone,
      role: "agent",
      status: "Approved",
      isDeleted: false,
    });

    if (!user) {
      return errorResponse(res, "Agent not found or not approved", 404);
    }
    // OPTIONAL: cooldown (30 sec) for future ref
    // if (user.otpExpiresAt && user.otpExpiresAt > new Date(Date.now() - 30 * 1000)) {
    //   return errorResponse(res, "Please wait before resending OTP", 429);
    // }
    const otp = Math.floor(100000 + Math.random() * 900000).toString();

    user.otp = otp;
    user.otpExpiresAt = new Date(Date.now() + 5 * 60 * 1000);
    await user.save();

    console.log("RESEND OTP:", otp);

    return res.json({
      success: true,
      message: "OTP resent successfully",
      data: otp,
    });
  } catch (err) {
    return errorResponse(res, "Failed to resend OTP", 500, err);
  }
};

const getAgentProfile = async (req, res) => {
  try {
    const agentId = req.user._id;

    const user = await User.findOne({
      _id: agentId,
      role: "agent",
      isDeleted: false,
    }).select(
      "firstName lastName phone email gender address profileImage updatedAt",
    );

    if (!user) {
      return errorResponse(res, "Agent not found", 404);
    }

    await logUserAction({
      userId: agentId,
      action: "GET_AGENT_PROFILE",
      model: "User",
      details: {
        fetchedFields: [
          "firstName",
          "lastName",
          "phone",
          "email",
          "gender",
          "address",
          "profileImage",
        ],
      },
      req,
    });

    return res.status(200).json({
      success: true,
      message: "Agent profile fetched successfully",
      data: {
        _id: user._id,
        name: `${user.firstName} ${user.lastName || ""}`.trim(),
        firstName: user.firstName,
        lastName: user.lastName || "",
        phone: user.phone || "",
        email: user.email || "",
        gender: user.gender || "other",
        address: user.address || {},
        profileImage: user.profileImage || null,
        updatedAt: user.updatedAt,
      },
    });
  } catch (err) {
    console.error("GET AGENT PROFILE ERROR:", err);
    return errorResponse(res, "Failed to fetch agent profile", 500, err);
  }
};

const updateAgentProfileDetails = async (req, res) => {
  try {
    const agentId = req.user._id;

    const allowedFields = [
      "firstName",
      "lastName",
      "email",
      "phone",
      "gender",
      "address",
    ];

    const updates = {};

    allowedFields.forEach((field) => {
      if (req.body[field] !== undefined) {
        updates[field] = req.body[field];
      }
    });

    // if (Object.keys(updates).length === 0) {
    //   return errorResponse(res, "No valid fields provided", 400);
    // }

    updates.updatedAt = new Date();

    const user = await User.findOneAndUpdate(
      {
        _id: agentId,
        role: "agent",
        isDeleted: false,
      },
      { $set: updates },
      { new: true },
    ).select("-password -deviceToken -playerId");

    if (!user) {
      return errorResponse(res, "Agent not found", 404);
    }

    await logUserAction({
      userId: agentId,
      action: "UPDATE_PROFILE_DETAILS",
      model: "User",
      details: { updatedFields: Object.keys(updates) },
      req,
    });

    return res.status(200).json({
      success: true,
      message: "Profile details updated successfully",
      data: user,
    });
  } catch (err) {
    console.error("UPDATE AGENT PROFILE DETAILS ERROR:", err);
    return errorResponse(res, "Failed to update profile details", 500, err);
  }
};

const updateAgentProfileImage = async (req, res) => {
  try {
    const agentId = req.user._id;

    // if (!req.file) {
    //   return errorResponse(res, "Profile image is required", 400);
    // }

    const profileImagePath = `/uploads/images/${req.file.filename}`;

    const user = await User.findOneAndUpdate(
      {
        _id: agentId,
        role: "agent",
        isDeleted: false,
      },
      {
        $set: {
          profileImage: profileImagePath,
          updatedAt: new Date(),
        },
      },
      { new: true },
    ).select("-password -deviceToken -playerId");

    if (!user) {
      return errorResponse(res, "Agent not found", 404);
    }

    await logUserAction({
      userId: agentId,
      action: "UPDATE_PROFILE_IMAGE",
      model: "User",
      details: {
        profileImage: profileImagePath,
      },
      req,
    });

    return res.status(200).json({
      success: true,
      message: "Profile image updated successfully",
      data: {
        profileImage: user.profileImage,
      },
    });
  } catch (err) {
    console.error("UPDATE AGENT PROFILE IMAGE ERROR:", err);
    return errorResponse(res, "Failed to update profile image", 500, err);
  }
};

const getAgentProfileWithHistory = async (req, res) => {
  try {
    const agentId = req.user._id;
    const orgId = req.user.orgId;

    /*  AGENT PROFILE */
    const agent = await User.findOne({
      _id: agentId,
      role: "agent",
      isDeleted: false,
    }).select("firstName lastName phone profileImage address");

    if (!agent) {
      return res.status(404).json({
        success: false,
        message: "Agent not found",
      });
    }

    /*  HISTORY */
    const history = await Task.find({
      assignedTo: agentId,
      orgId,
      isDeleted: false,
      status: { $in: ["Completed", "Closed"] },
    })
      .select("customer completedAt")
      .sort({ completedAt: -1 })
      .limit(20); // production-safe limit

    return res.status(200).json({
      success: true,
      data: {
        agent: {
          name: `${agent.firstName} ${agent.lastName || ""}`.trim(),
          phone: agent.phone,
          profileImage: agent.profileImage || null,
          address: agent.address || null,
        },
        history: history.map((task) => ({
          customerName: task.customer?.name || "--",
          address: task.customer?.address || "--",
          completedAt: task.completedAt,
        })),
      },
    });
  } catch (err) {
    console.error("GET AGENT PROFILE HISTORY ERROR:", err.message, err);
    return res.status(500).json({
      success: false,
      message: "Failed to fetch agent profile",
    });
  }
};

// const getUsers = async (req, res) => {
//   try {
//     const { role, page = 1, limit = 20 } = req.query;
//     const orgId = req.user.orgId;

//     const query = {
//       role : "doctor",
//       orgId,
//       isDeleted: false,
//     };

//     // Optional role filter
//     if (role) {
//       query.role = role;
//     }

//     const skip = (page - 1) * limit;

//     const [users, total] = await Promise.all([
//       User.find(query)
//         .select("firstName lastName email phone role status")
//         .sort({ createdAt: -1 })
//         .skip(skip)
//         .limit(Number(limit)),

//       User.countDocuments(query),
//     ]);

//     return res.status(200).json({
//       success: true,
//       total,
//       page: Number(page),
//       limit: Number(limit),
//       data: users,
//     });
//   } catch (error) {
//     console.error("getUsers error:", error);
//     return errorResponse(res, "Failed to fetch users", 500);
//   }
// };

const getUsers = async (req, res) => {
  try {
    const { page = 1, limit = 20 } = req.query;
    const orgId = req.user.orgId;

    const query = {
      role: "doctor",
      orgId,
      isDeleted: false,
    };

    const skip = (page - 1) * limit;

    const [users, total] = await Promise.all([
      User.find(query)
        .populate("specializations", "name")
        .populate("branch", "branchName")
        .select(
          "firstName lastName email phone role status specializations branch consultationFee workingHours lunchBreak",
        )
        .sort({ createdAt: -1 })
        .skip(skip)
        .limit(Number(limit)),

      User.countDocuments(query),
    ]);

    return res.status(200).json({
      success: true,
      total,
      page: Number(page),
      limit: Number(limit),
      data: users,
    });
  } catch (error) {
    console.error("getDoctors error:", error);
    return errorResponse(res, "Failed to fetch doctors", 500);
  }
};

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

    //  Validate Mongo ID
    // if (!mongoose.Types.ObjectId.isValid(id)) {
    //   return errorResponse(res, 400, "Invalid doctor id");
    // }

    //  Fetch only if role is doctor
    const doctor = await User.findOne({
      _id: id,
      role: "doctor",
      isDeleted: { $ne: true },
    })
      .select(
        "firstName lastName phone email profileImage specialization experience education languages about designation",
      )
      .populate("designation", "name")
      .lean();

    if (!doctor) {
      return errorResponse(res, 404, "Doctor not found");
    }

    //  Safe defaults for frontend
    const response = {
      id: doctor._id,
      firstName: doctor.firstName,
      lastName: doctor.lastName,
      phone: doctor.phone,
      email: doctor.email,
      profileImage: doctor.profileImage,
      designation: doctor.designation?.name || "Consultant",
      specialization: doctor.specialization || "General Physician",
      experience: doctor.experience || "5 Years",
      education: doctor.education || "MBBS",
      languages: doctor.languages?.length ? doctor.languages : ["English"],
      about: doctor.about || "Experienced medical professional",
    };

    return res.status(200).json({
      success: true,
      message: "Doctor profile fetched successfully",
      data: response,
    });
  } catch (error) {
    console.error("Get Doctor Profile Error:", error);
    return errorResponse(res, 500, "Internal server error");
  }
};

const getDoctors = async (req, res) => {
  try {
    const { orgId } = req.query;

    if (!orgId) {
      return res.status(400).json({
        success: false,
        message: "Organization ID is required",
      });
    }

    const doctors = await User.find({
      role: "doctor",
      orgId: orgId,
      isDeleted: false,
      status: "Approved",
    })
      .select("firstName lastName profileImage consultationFee specializations")
      .populate("specializations", "name")
      .lean();

    res.json({
      success: true,
      data: doctors,
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: error.message,
    });
  }
};

// sessions api
// const getCurrentUser = async (req, res) => {
//   if (!req.session.user) {
//     return res.status(401).json({ success: false });
//   }

//   const user = await User.findById(req.session.user.id).select("-password");

//   res.json({
//     success: true,
//     user: {
//       ...user.toObject(),
//       permissions: req.session.user.permissions,
//     },
//   });
// };

 
const getCurrentUser = async (req, res) => {
  const client = await pool.connect();

  try {
    // 🔹 Check session
    if (!req.session?.user) {
      return res.status(401).json({ success: false });
    }

    const userId = parseInt(req.session.user.id, 10);

    if (!userId || isNaN(userId)) {
      return res.status(401).json({ success: false });
    }

    // 🔹 Fetch user (exclude password)
    const result = await client.query(
      `
      SELECT 
        id,
        first_name AS "firstName",
        last_name AS "lastName",
        email,
        phone,
        gender,
        role,
        status,
        org_id AS "orgId",
        department_id AS "department",
        designation_id AS "designation",
        reporting_manager AS "reportingManager",
        created_at AS "createdAt",
        updated_at AS "updatedAt"
      FROM users
      WHERE id = $1 AND is_deleted = FALSE
      LIMIT 1;
      `,
      [userId],
    );

    if (result.rowCount === 0) {
      return res.status(401).json({ success: false });
    }

    const user = result.rows[0];

    // 🔹 Response (same structure as Mongo)
    return res.json({
      success: true,
      user: {
        ...user,
        permissions: req.session.user.permissions,
      },
    });
  } catch (err) {
    console.error("Get current user error:", err);
    return errorResponse(res, "Failed to fetch current user", 500, err);
  } finally {
    client.release();
  }
};

// ------------------ BULK UPDATE USER PASSWORDS ------------------
const bulkUpdateUserPasswords = async (req, res) => {
  const client = await pool.connect();

  try {
    const { users } = req.body; // Expecting array of { userId, new_password }
    
    // Check permission
    const currentUserRole = req.session?.user?.role?.toLowerCase() || req.user?.role?.toLowerCase();
    const allowedRolesForPasswordUpdate = ['admin', 'hr', 'superadmin', 'super_admin'];
    
    if (!allowedRolesForPasswordUpdate.includes(currentUserRole)) {
      return res.status(403).json({
        success: false,
        message: "You don't have permission to update user passwords",
      });
    }
    
    if (!users || !Array.isArray(users) || users.length === 0) {
      return res.status(400).json({
        success: false,
        message: "Users array is required",
      });
    }
    
    const results = [];
    const errors = [];
    
    await client.query('BEGIN');
    
    for (const user of users) {
      try {
        const { userId, new_password } = user;
        
        if (!userId || !new_password) {
          errors.push({ userId, error: "User ID and new password are required" });
          continue;
        }
        
        if (new_password.length < 6) {
          errors.push({ userId, error: "Password must be at least 6 characters" });
          continue;
        }
        
        // Check if user exists
        const userCheck = await client.query(
          `SELECT id, email FROM users WHERE id = $1 AND is_deleted = false`,
          [userId]
        );
        
        if (userCheck.rowCount === 0) {
          errors.push({ userId, error: "User not found" });
          continue;
        }
        
        // Hash and update password
        const hashedPassword = await bcrypt.hash(new_password, 10);
        
        await client.query(
          `UPDATE users 
           SET password = $1, 
               must_change_password = $2,
               updated_by = $3,
               updated_at = NOW()
           WHERE id = $4`,
          [hashedPassword, true, req.user?.id || req.session?.user?.id, userId]
        );
        
        results.push({
          userId,
          email: userCheck.rows[0].email,
          status: "success"
        });
        
      } catch (userErr) {
        errors.push({ userId: user.userId, error: userErr.message });
      }
    }
    
    await client.query('COMMIT');
    
    // Log bulk action
    await logUserAction({
      userId: req.user?.id || req.session?.user?.id,
      action: "BULK_UPDATE_PASSWORDS",
      model: "User",
      details: { 
        total: users.length, 
        successful: results.length, 
        failed: errors.length 
      },
      req,
    });
    
    return res.json({
      success: true,
      message: `Password updated for ${results.length} out of ${users.length} users`,
      data: {
        successful: results,
        failed: errors
      }
    });
    
  } catch (err) {
    await client.query('ROLLBACK');
    console.error("Bulk update passwords error:", err);
    return errorResponse(res, "Failed to update passwords", 500);
  } finally {
    client.release();
  }
};

// ------------------ UPDATE USER PASSWORD ONLY (FOR SPECIFIC ROLES) ------------------
const updateUserPassword = async (req, res) => {
  const client = await pool.connect();

  try {
    const userId = req.params.id;
    const { new_password, confirm_password } = req.body;
    
    // Check if current user has permission to update passwords
    const currentUserRole = req.session?.user?.role?.toLowerCase() || req.user?.role?.toLowerCase();
    const allowedRolesForPasswordUpdate = ['admin', 'hr', 'superadmin', 'super_admin'];
    
    if (!allowedRolesForPasswordUpdate.includes(currentUserRole)) {
      return res.status(403).json({
        success: false,
        message: "You don't have permission to update user passwords",
      });
    }
    
    // Validate new password
    if (!new_password) {
      return res.status(400).json({
        success: false,
        message: "New password is required",
      });
    }
    
    if (new_password.length < 6) {
      return res.status(400).json({
        success: false,
        message: "New password must be at least 6 characters long",
      });
    }
    
    if (confirm_password && new_password !== confirm_password) {
      return res.status(400).json({
        success: false,
        message: "Passwords do not match",
      });
    }
    
    // Check if user exists
    const userCheck = await client.query(
      `SELECT id, email, first_name, last_name, role FROM users WHERE id = $1 AND is_deleted = false`,
      [userId]
    );
    
    if (userCheck.rowCount === 0) {
      return errorResponse(res, "User not found", 404);
    }
    
    const user = userCheck.rows[0];
    
    // Hash new password
    const hashedPassword = await bcrypt.hash(new_password, 10);
    
    // Update password
    const updateQuery = `
      UPDATE users
      SET password = $1,
          must_change_password = $2,
          updated_by = $3,
          updated_at = NOW()
      WHERE id = $4
      RETURNING id, email, first_name, last_name
    `;
    
    const result = await client.query(updateQuery, [
      hashedPassword,
      true, // Force password change on next login
      req.user?.id || req.session?.user?.id || null,
      userId
    ]);
    
    // Log action
    await logUserAction({
      userId: req.user?.id || req.session?.user?.id,
      action: "UPDATE_USER_PASSWORD",
      model: "User",
      details: { targetUserId: userId, targetEmail: user.email },
      req,
    });
    
    return res.json({
      success: true,
      message: "User password updated successfully",
      data: {
        id: result.rows[0].id,
        email: result.rows[0].email,
        name: `${result.rows[0].first_name} ${result.rows[0].last_name || ''}`.trim(),
        must_change_password: true
      }
    });
    
  } catch (err) {
    console.error("Update user password error:", err);
    return errorResponse(res, "Failed to update user password", 500);
  } finally {
    client.release();
  }
};

module.exports = {
  getCurrentUser,
  registerUser,
  loginUser,
  getAllUsers,
  getUserById,
  updateUser,
  deactivateUser,
  logoutFromDevice,
  profileImageUpload,
  forgotPassword,
  validateToken,
  deleteUser,
  forgotPassword,
  updateUserStatus,
  // getAgents,
  sendAgentOtp,
  verifyAgentOtp,
  resendAgentOtp,
  getAgentProfile,
  updateAgentProfileDetails,
  updateAgentProfileImage,
  changePassword,
  getAgentProfileWithHistory,
  getUsers,
  getDoctorProfile,
  getDoctors,
  updateUserPassword,        // Add this
  bulkUpdateUserPasswords,   // Add this (optional)
};
