const pool = require('../config/db');
const asyncHandler = require('../middlewares/asyncHandler');
const { getLocationFilterFromRequest } = require('../utils/auditFilterHelper');
const {
  getAllUsers,
  getUserById,
  getUserByEmployeeId,
  createUser,
  updateUser,
  deleteUser,
  getUserSnapshotForLog,
  insertUserCreationLog,
  insertUserUpdateLog,
  insertUserDeleteLog,
  getUserLogs
} = require('../repositories/userRepository');

const MAX_USER_PHOTO_SIZE_MB = 10;
const MAX_USER_PHOTO_SIZE_BYTES = MAX_USER_PHOTO_SIZE_MB * 1024 * 1024;

// Get all users (optionally filtered by master dashboard country, site, work area)
exports.getAllUsers = asyncHandler(async (req, res) => {
    const filter = getLocationFilterFromRequest(req);
    const rows = await getAllUsers(filter);
    res.status(200).json({ success: true, data: rows });
});

// Get user by ID
exports.getUserById = asyncHandler(async (req, res) => {
    const { id } = req.params;
    const user = await getUserById(id);
    
    if (!user) {
        return res.status(404).json({ success: false, message: 'User not found' });
    }
    
    res.status(200).json({ success: true, data: user });
});

// Create user
exports.createUser = asyncHandler(async (req, res) => {
    const { employee_id, employee_name, email_id, phonenumber, department_id, location_id, password, role_ids, photo_base64 } = req.body;
    
    if (!employee_id || !employee_name || !email_id || !password || !phonenumber || !department_id || !location_id) {
        return res.status(400).json({ success: false, message: 'employee_id, employee_name, email_id, phonenumber, department_id, location_id, and password are required' });
    }
    if (!role_ids || !Array.isArray(role_ids) || role_ids.length === 0) {
        return res.status(400).json({ success: false, message: 'At least one role is required' });
    }

    // Check if employee_id already exists to avoid duplicate key error
    const existingByEmployeeId = await getUserByEmployeeId(employee_id);
    if (existingByEmployeeId) {
        return res.status(409).json({ success: false, message: `Employee ID '${employee_id}' is already in use` });
    }
    
    const connection = await pool.getConnection();
    try {
        await connection.beginTransaction();
        
        let photoBuffer = null;
        if (photo_base64) {
            const base64Data = photo_base64.replace(/^data:image\/\w+;base64,/, '');
            photoBuffer = Buffer.from(base64Data, 'base64');
            if (photoBuffer.length > MAX_USER_PHOTO_SIZE_BYTES) {
                await connection.rollback();
                return res.status(400).json({ success: false, message: `User image must be ${MAX_USER_PHOTO_SIZE_MB} MB or smaller` });
            }
        }
        const userData = {
            employee_id,
            status_id: 1,
            employee_name,
            email_id,
            phonenumber,
            department_id,
            location_id,
            password,
            photo: photoBuffer
        };
        const userId = await createUser(userData, role_ids, connection);

        // User creation log: user_id in users_logs maps to users.user_id; log when admin creates user
        const createdByUserId = req.user?.userId;
        if (createdByUserId) {
          const snapshot = await getUserSnapshotForLog(userId, connection);
          if (snapshot) {
            await insertUserCreationLog(userId, createdByUserId, snapshot, connection);
          }
        }

        await connection.commit();
        res.status(201).json({ success: true, message: 'User created successfully', data: { user_id: userId } });
    } catch (error) {
        await connection.rollback();
        if (error.code === 'ER_DUP_ENTRY') {
            return res.status(409).json({ success: false, message: 'Employee ID or email already exists' });
        }
        throw error;
    } finally {
        connection.release();
    }
});

// Update user
exports.updateUser = asyncHandler(async (req, res) => {
    const { id } = req.params;
    const { status_id, employee_name, email_id, phonenumber, department_id, location_id, password, role_ids } = req.body;
    
    const updateData = {};
    if (status_id !== undefined) updateData.status_id = status_id;
    if (employee_name !== undefined) updateData.employee_name = employee_name;
    if (email_id !== undefined) updateData.email_id = email_id;
    if (phonenumber !== undefined) updateData.phonenumber = phonenumber;
    if (department_id !== undefined) updateData.department_id = department_id;
    if (location_id !== undefined) updateData.location_id = location_id;
    if (password !== undefined) updateData.password = password;
    
    if (Object.keys(updateData).length === 0 && !role_ids) {
        return res.status(400).json({ success: false, message: 'No fields to update' });
    }
    
    const connection = await pool.getConnection();
    try {
        await connection.beginTransaction();
        
        const updated = await updateUser(id, updateData, role_ids, connection);
        
        if (!updated) {
            await connection.rollback();
            return res.status(404).json({ success: false, message: 'User not found' });
        }

        // User update log: insert into users_logs with action e.g. "UPDATED by EMP001"
        const updatedByUserId = req.user?.userId;
        if (updatedByUserId) {
            const snapshot = await getUserSnapshotForLog(id, connection);
            if (snapshot) {
                await insertUserUpdateLog(id, updatedByUserId, snapshot, connection);
            }
        }
        
        await connection.commit();
        res.status(200).json({ success: true, message: 'User updated successfully' });
    } catch (error) {
        await connection.rollback();
        throw error;
    } finally {
        connection.release();
    }
});

// Get user logs (users_logs table; optional query: limit, offset, action=CREATED|UPDATED|DELETED)
exports.getUserLogs = asyncHandler(async (req, res) => {
  const { limit, offset, action } = req.query;
  const rows = await getUserLogs({ limit, offset, action });
  res.status(200).json({ success: true, data: rows });
});

// Delete user (soft delete - set status_id to 2)
exports.deleteUser = asyncHandler(async (req, res) => {
    const { id } = req.params;
    
    // Check if user exists
    const user = await getUserById(id);
    if (!user) {
        return res.status(404).json({ success: false, message: 'User not found' });
    }
    
    const connection = await pool.getConnection();
    try {
        await connection.beginTransaction();
        
        // Update status_id to 2 (deleted/inactive) instead of deleting
        const updateData = { status_id: 2 };
        const updated = await updateUser(id, updateData, null, connection);
        
        if (!updated) {
            await connection.rollback();
            return res.status(404).json({ success: false, message: 'User not found' });
        }

        // User delete log: insert into users_logs with action e.g. "DELETED by EMP001"
        const deletedByUserId = req.user?.userId;
        if (deletedByUserId) {
            const snapshot = await getUserSnapshotForLog(id, connection);
            if (snapshot) {
                await insertUserDeleteLog(id, deletedByUserId, snapshot, connection);
            }
        }
        
        await connection.commit();
        res.status(200).json({ success: true, message: 'User deleted successfully' });
    } catch (error) {
        await connection.rollback();
        throw error;
    } finally {
        connection.release();
    }
});

