const User = require('../models/User');
const Role = require('../models/Role');
const AuditLog = require('../models/AuditLog');
const AuthService = require('./auth.service');
const { AppError } = require('../middleware/errorHandler');

class UserService {
    /**
     * Get all users
     */
    static getAllUsers() {
        const users = User.getAll();

        // Remove password hashes from response
        return users.map(user => {
            const { password_hash, ...userWithoutPassword } = user;
            return userWithoutPassword;
        });
    }

    /**
     * Get user by ID
     */
    static getUserById(id) {
        const user = User.getById(id);

        if (!user) {
            throw new AppError('User not found', 404);
        }

        const { password_hash, ...userWithoutPassword } = user;
        return userWithoutPassword;
    }

    /**
     * Create new user
     */
    static async createUser(userData, createdByUserId, ipAddress) {
        // Validate required fields
        if (!userData.username || !userData.email || !userData.password || !userData.role_id) {
            throw new AppError('Missing required fields', 400);
        }

        // Check if username already exists
        const existingUser = User.getByUsername(userData.username);
        if (existingUser) {
            throw new AppError('Username already exists', 409);
        }

        // Check if email already exists
        const existingEmail = User.getByEmail(userData.email);
        if (existingEmail) {
            throw new AppError('Email already exists', 409);
        }

        // Validate role exists
        const role = Role.getById(userData.role_id);
        if (!role) {
            throw new AppError('Invalid role', 400);
        }

        // Hash password
        const password_hash = await AuthService.hashPassword(userData.password);

        // Create user
        const newUser = User.create({
            username: userData.username,
            email: userData.email,
            password_hash,
            role_id: userData.role_id,
            first_name: userData.first_name,
            last_name: userData.last_name,
            is_active: userData.is_active !== undefined ? userData.is_active : 1,
            must_change_password: userData.must_change_password !== undefined ? userData.must_change_password : 1
        });

        // Log action
        AuditLog.logUserAction(
            createdByUserId,
            'CREATE_USER',
            'user',
            newUser.id,
            null,
            { username: newUser.username, role: role.name },
            ipAddress
        );

        const { password_hash: _, ...userWithoutPassword } = newUser;
        return userWithoutPassword;
    }

    /**
     * Update user
     */
    static async updateUser(id, userData, updatedByUserId, ipAddress) {
        // Get existing user
        const existingUser = User.getById(id);
        if (!existingUser) {
            throw new AppError('User not found', 404);
        }

        // Check if username is being changed and already exists
        if (userData.username && userData.username !== existingUser.username) {
            const userWithUsername = User.getByUsername(userData.username);
            if (userWithUsername) {
                throw new AppError('Username already exists', 409);
            }
        }

        // Check if email is being changed and already exists
        if (userData.email && userData.email !== existingUser.email) {
            const userWithEmail = User.getByEmail(userData.email);
            if (userWithEmail) {
                throw new AppError('Email already exists', 409);
            }
        }

        // Validate role if being changed
        if (userData.role_id) {
            const role = Role.getById(userData.role_id);
            if (!role) {
                throw new AppError('Invalid role', 400);
            }
        }

        // Hash password if being changed
        if (userData.password) {
            userData.password_hash = await AuthService.hashPassword(userData.password);
            delete userData.password;
        }

        // Update user
        const updatedUser = User.update(id, userData);

        // Log action
        AuditLog.logUserAction(
            updatedByUserId,
            'UPDATE_USER',
            'user',
            id,
            { username: existingUser.username },
            { username: updatedUser.username },
            ipAddress
        );

        const { password_hash, ...userWithoutPassword } = updatedUser;
        return userWithoutPassword;
    }

    /**
     * Delete user
     */
    static deleteUser(id, deletedByUserId, ipAddress) {
        // Get existing user
        const existingUser = User.getById(id);
        if (!existingUser) {
            throw new AppError('User not found', 404);
        }

        // Prevent deletion of last super admin
        if (existingUser.role_name === 'super_admin') {
            const allUsers = User.getAll();
            const superAdmins = allUsers.filter(u => u.role_name === 'super_admin');
            if (superAdmins.length === 1) {
                throw new AppError('Cannot delete the last super admin', 403);
            }
        }

        // Delete user
        const deleted = User.delete(id);

        if (deleted) {
            // Log action
            AuditLog.logUserAction(
                deletedByUserId,
                'DELETE_USER',
                'user',
                id,
                { username: existingUser.username },
                null,
                ipAddress
            );
        }

        return deleted;
    }

    /**
     * Assign role to user
     */
    static assignRole(userId, roleId, assignedByUserId, ipAddress) {
        // Get user
        const user = User.getById(userId);
        if (!user) {
            throw new AppError('User not found', 404);
        }

        // Validate role
        const role = Role.getById(roleId);
        if (!role) {
            throw new AppError('Invalid role', 400);
        }

        // Prevent changing role of last super admin
        if (user.role_name === 'super_admin' && role.name !== 'super_admin') {
            const allUsers = User.getAll();
            const superAdmins = allUsers.filter(u => u.role_name === 'super_admin');
            if (superAdmins.length === 1) {
                throw new AppError('Cannot change role of the last super admin', 403);
            }
        }

        // Update role
        const oldRole = user.role_name;
        const updatedUser = User.update(userId, { role_id: roleId });

        // Log action
        AuditLog.logUserAction(
            assignedByUserId,
            'ASSIGN_ROLE',
            'user',
            userId,
            { role: oldRole },
            { role: role.name },
            ipAddress
        );

        const { password_hash, ...userWithoutPassword } = updatedUser;
        return userWithoutPassword;
    }

    /**
     * Activate/Deactivate user
     */
    static toggleUserStatus(userId, isActive, updatedByUserId, ipAddress) {
        // Get user
        const user = User.getById(userId);
        if (!user) {
            throw new AppError('User not found', 404);
        }

        // Prevent deactivating last super admin
        if (user.role_name === 'super_admin' && !isActive) {
            const allUsers = User.getAll();
            const activeSuperAdmins = allUsers.filter(u => u.role_name === 'super_admin' && u.is_active);
            if (activeSuperAdmins.length === 1) {
                throw new AppError('Cannot deactivate the last super admin', 403);
            }
        }

        // Update status
        const updatedUser = User.update(userId, { is_active: isActive ? 1 : 0 });

        // Log action
        AuditLog.logUserAction(
            updatedByUserId,
            isActive ? 'ACTIVATE_USER' : 'DEACTIVATE_USER',
            'user',
            userId,
            { is_active: user.is_active },
            { is_active: isActive },
            ipAddress
        );

        const { password_hash, ...userWithoutPassword } = updatedUser;
        return userWithoutPassword;
    }
}

module.exports = UserService;
