<?php

namespace FleekDash\Controllers;

use FleekDash\Core\I18nManager;
use FleekDash\Core\PermissionMiddleware;
use FleekDash\Realtime\RealtimeEventOutboxService;
use FleekDash\Services\ResponseService;
use FleekDash\Services\WordPressLocaleSyncService;
use FleekDash\Utils\AvatarHelper;
use WP_User_Query;

// Load debug helpers
if (!function_exists('fleekdash_log_debug')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}



/**
 * Class UserController
 *
 * Handles user-related API endpoints.
 *
 * @package FleekDash\Controllers
 */
class UserController // NOSONAR php:S1448 - User API orchestration; split would require route/API refactor
{
    private const MSG_FAILED_CREATE_USER = 'Failed to create user: ';
    private const MSG_USER_NOT_FOUND = 'User not found';
    private const MSG_EMAIL_EXISTS = 'Email already exists';

    /**
     * Get a paginated list of users
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function index($request)
    {
        try {
            $perm_check = PermissionMiddleware::checkWithFallback('user_management.view', []);
            if (!$perm_check['success']) {
                return ResponseService::error(
                    'You do not have permission to view users',
                    null,
                    403
                );
            }

            $page = (int) ($request->get_param('page') ?? 1);
            $per_page = (int) ($request->get_param('per_page') ?? 10);
            $search = $request->get_param('search');
            $orderby = $request->get_param('orderby') ?? 'ID';
            $order = strtoupper($request->get_param('order') ?? 'ASC');
            $role = $request->get_param('role');

            $args = [
                'number' => $per_page,
                'paged' => $page,
                'orderby' => $orderby,
                'order' => $order,
                'search' => $search ? '*' . $search . '*' : '',
                'search_columns' => ['user_login', 'user_email', 'user_nicename', 'display_name']
            ];

            if (!empty($role)) {
                $args['role'] = $role;
            }

            // V2.2 FIX: Disable cache for WP_User_Query on manual refresh
            $is_manual_refresh = $request->get_param('_t') !== null;
            if ($is_manual_refresh) {
                $args['cache_results'] = false; // Disable object cache for this query
                fleekdash_log_debug('Users query cache disabled for manual refresh');
            }

            // Get users
            $query = new WP_User_Query($args);
            $results = $query->get_results();

            // Bulk-prime user object + meta caches so the get_user_meta() calls
            // in formatUser() do not run one query per user (N+1). WP_User_Query
            // skips this priming when cache_results is disabled (manual refresh).
            $this->primeUserMetaCaches($results);

            $users = array_map([$this, 'formatUser'], $results);

            // Get total users for pagination
            $total = $query->get_total();

            return ResponseService::paginate($users, [
                'current_page' => $page,
                'per_page' => $per_page,
                'total' => $total,
                'total_pages' => ceil($total / $per_page)
            ]);

        } catch (\Exception $e) {
            return ResponseService::error('Failed to fetch users: ' . $e->getMessage());
        }
    }

    /**
     * Validate show user access. Returns error response or null if allowed.
     */
    private function validateShowAccess(int $user_id, \WP_User|false $user): ?\WP_REST_Response // NOSONAR php:S1142 - multiple returns for validation clarity
    {
        if (!$user) {
            return ResponseService::error(self::MSG_USER_NOT_FOUND, null, 404);
        }

        $is_self = $user_id === \get_current_user_id();
        if (!$is_self) {
            $perm_check = PermissionMiddleware::check('user_management.view');
            if (!$perm_check['allowed']) {
                return ResponseService::error('You do not have permission to view this user', null, 403);
            }
        }

        return null;
    }

    /**
     * Get a single user by ID
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function show(\WP_REST_Request $request)
    {
        try {
            $user_id = (int) $request->get_param('id');
            $user = \get_userdata($user_id);
            $err = $this->validateShowAccess($user_id, $user);
            if ($err !== null) {
                return $err;
            }
            return ResponseService::success($this->formatUser($user));
        } catch (\Exception $e) {
            return ResponseService::error('Failed to fetch user: ' . $e->getMessage());
        }
    }

    /**
     * Get current logged in user
     *
     * @param \WP_REST_Request $_request
     * @return \WP_REST_Response
     */
    public function me(\WP_REST_Request $_request) // NOSONAR php:S1172 - WP REST callback signature
    {
        try {
            // Get current user (works with both session and cookie auth)
            $current_user = \wp_get_current_user();

            // If no user is found, return empty user data instead of error
            if (!$current_user || $current_user->ID === 0) {
                return ResponseService::success([
                    'id' => 0,
                    'name' => '',
                    'email' => '',
                    'first_name' => '',
                    'last_name' => '',
                    'nickname' => '',
                    'description' => '',
                    'display_name' => '',
                    'avatar' => '',
                    'roles' => []
                ]);
            }

            return ResponseService::success($this->formatUser($current_user));

        } catch (\Exception $e) {
            return ResponseService::error('Failed to fetch current user: ' . $e->getMessage());
        }
    }

    /**
     * Validate store params. Returns error response or null if valid.
     */
    private function validateStoreParams(\WP_REST_Request $request): ?\WP_REST_Response // NOSONAR php:S1142 - multiple returns for validation clarity
    {
        $perm_check = PermissionMiddleware::check('user_management.create');
        if (!$perm_check['allowed']) {
            return ResponseService::error('You do not have permission to create users', null, 403);
        }
        $username = $request->get_param('username');
        $email = $request->get_param('email');
        $password = $request->get_param('password');
        $role = $request->get_param('role') ?? 'subscriber';
        if (empty($username) || empty($email) || empty($password)) {
            return ResponseService::error('Username, email and password are required', null, 400);
        }
        if (username_exists($username)) {
            return ResponseService::error('Username already exists', null, 400);
        }
        if (\email_exists($email)) {
            return ResponseService::error(self::MSG_EMAIL_EXISTS, null, 400);
        }
        if (!empty($role) && !\get_role($role)) {
            return ResponseService::error('Invalid role specified', null, 400);
        }
        return null;
    }

    /**
     * Execute user creation after validation.
     */
    private function executeStore(\WP_REST_Request $request): \WP_REST_Response
    {
        $username = $request->get_param('username');
        $email = $request->get_param('email');
        $password = $request->get_param('password');
        $first_name = $request->get_param('first_name');
        $last_name = $request->get_param('last_name');
        $role = $request->get_param('role') ?? 'subscriber';

        $user_id = \wp_create_user($username, $password, $email);
        if (\is_wp_error($user_id)) {
            return ResponseService::error(self::MSG_FAILED_CREATE_USER . $user_id->get_error_message(), null, 400);
        }

        $user = new \WP_User($user_id);
        $user->set_role($role);
        if (!empty($first_name)) {
            \update_user_meta($user_id, 'first_name', $first_name);
        }
        if (!empty($last_name)) {
            \update_user_meta($user_id, 'last_name', $last_name);
        }
        if (!empty($first_name) && !empty($last_name)) {
            \wp_update_user([
                'ID' => $user_id,
                'display_name' => $first_name . ' ' . $last_name
            ]);
        }
        return ResponseService::success($this->formatUser($user), 'User created successfully', 201);
    }

    /**
     * Create a new user
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function store($request)
    {
        try {
            $err = $this->validateStoreParams($request);
            if ($err !== null) {
                return $err;
            }
            return $this->executeStore($request);
        } catch (\Exception $e) {
            return ResponseService::error(self::MSG_FAILED_CREATE_USER . $e->getMessage());
        }
    }

    /**
     * Apply role update if requested and permitted.
     *
     * @param \WP_REST_Request $request
     * @param int $user_id Target user ID
     * @param int $current_user_id Current user ID
     * @param \WP_User $user User object
     * @return \WP_REST_Response|null Error response or null on success
     */
    private function applyRoleUpdate($request, int $user_id, int $current_user_id, $user): ?\WP_REST_Response // NOSONAR php:S1142 - multiple returns for validation clarity
    {
        if ($request->get_param('role') === null) {
            return null;
        }

        $perm_check = PermissionMiddleware::check('user_management.promote');
        if (!$perm_check['allowed']) {
            return ResponseService::error('You do not have permission to promote users', null, 403);
        }
        $new_role = \sanitize_text_field($request->get_param('role'));
        if (!\get_role($new_role)) {
            return ResponseService::error('Invalid role specified', null, 400);
        }
        if ($user_id === $current_user_id && \current_user_can('administrator')) {
            return ResponseService::error('You cannot change your own role', null, 400);
        }
        $user->set_role($new_role);
        return null;
    }

    /**
     * Build user_data array from request params (email, password, display_name).
     *
     * @param \WP_REST_Request $request
     * @param int $user_id User ID
     * @return array{user_data: array, error: \WP_REST_Response|null}
     */
    private function buildUserDataFromRequest($request, int $user_id): array
    {
        $user_data = ['ID' => $user_id];
        $error = null;

        if ($request->get_param('email') !== null) {
            $new_email = $request->get_param('email');
            if (\email_exists($new_email) && (int) \email_exists($new_email) !== $user_id) {
                $error = ResponseService::error(self::MSG_EMAIL_EXISTS, null, 400);
            } else {
                $user_data['user_email'] = $new_email;
            }
        }
        if ($error === null && $request->get_param('password') !== null) {
            $user_data['user_pass'] = $request->get_param('password');
        }
        if ($error === null && $request->get_param('display_name') !== null) {
            $user_data['display_name'] = $request->get_param('display_name');
        }

        return ['user_data' => $user_data, 'error' => $error];
    }

    /**
     * Apply user meta updates (first_name, last_name, nickname, description).
     *
     * @param \WP_REST_Request $request
     * @param int $user_id User ID
     */
    private function applyUserMetaUpdates($request, int $user_id): void
    {
        $meta_fields = ['first_name', 'last_name', 'nickname', 'description'];
        foreach ($meta_fields as $field) {
            $value = $request->get_param($field);
            if ($value !== null) {
                \update_user_meta($user_id, $field, $value);
            }
        }
    }

    /**
     * Apply registered_date update if provided.
     *
     * @param \WP_REST_Request $request
     * @param int $user_id User ID
     * @return \WP_REST_Response|null Error response or null on success
     */
    private function applyRegisteredDateUpdate($request, int $user_id): ?\WP_REST_Response // NOSONAR php:S1142 - validation returns
    {
        $registered_date = $request->get_param('registered_date');
        if ($registered_date === null) {
            return null;
        }
        $registered_date = \sanitize_text_field($registered_date);
        $date_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $registered_date);
        if (!$date_obj) {
            return ResponseService::error('Invalid date format. Use: YYYY-MM-DD HH:MM:SS', null, 400);
        }
        global $wpdb;
        $updated = $wpdb->update(
            $wpdb->users,
            ['user_registered' => $registered_date],
            ['ID' => $user_id],
            ['%s'],
            ['%d']
        );
        if ($updated === false) {
            fleekdash_log_error("Failed to update registered_date for user {$user_id}");
            return ResponseService::error('Failed to update registered date', null, 500);
        }
        \wp_cache_delete($user_id, 'users');
        \wp_cache_delete($user_id, 'user_meta');
        \clean_user_cache($user_id);
        fleekdash_log_debug("User {$user_id} registered_date updated to {$registered_date}");
        return null;
    }

    /**
     * Update an existing user
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function update($request) // NOSONAR php:S1142 - multiple returns for validation/error handling
    {
        try {
            $user_id = (int) $request->get_param('id');
            $user = \get_userdata($user_id);
            if (!$user) {
                return ResponseService::error(self::MSG_USER_NOT_FOUND, null, 404);
            }

            $current_user_id = \get_current_user_id();
            fleekdash_log_debug("UserController::update - Current User ID: " . $current_user_id);
            fleekdash_log_debug("UserController::update - Target User ID: " . $user_id);
            fleekdash_log_debug("UserController::update - is_user_logged_in: " . (\is_user_logged_in() ? 'true' : 'false'));

            $role_error = $this->applyRoleUpdate($request, $user_id, $current_user_id, $user);
            if ($role_error !== null) {
                return $role_error;
            }

            ['user_data' => $user_data, 'error' => $build_error] = $this->buildUserDataFromRequest($request, $user_id);
            if ($build_error !== null) {
                return $build_error;
            }

            $this->applyUserMetaUpdates($request, $user_id);

            $date_error = $this->applyRegisteredDateUpdate($request, $user_id);
            if ($date_error !== null) {
                return $date_error;
            }

            if (count($user_data) > 1) {
                $result = \wp_update_user($user_data);
                if (\is_wp_error($result)) {
                    return ResponseService::error('Failed to update user: ' . $result->get_error_message(), null, 400);
                }
            }

            $user = \get_userdata($user_id);
            return ResponseService::success($this->formatUser($user), 'User updated successfully');
        } catch (\Exception $e) {
            return ResponseService::error('Failed to update user: ' . $e->getMessage());
        }
    }

    /**
     * Build REST error response for destroy endpoint.
     */
    private function destroyError(string $message, int $code): \WP_REST_Response
    {
        return new \WP_REST_Response(['success' => false, 'error' => $message], $code);
    }

    /**
     * Validate destroy params. Returns error response or null.
     */
    private function validateDestroyParams(\WP_REST_Request $request): ?\WP_REST_Response // NOSONAR php:S1142 - multiple returns for validation
    {
        $perm_check = PermissionMiddleware::check('user_management.delete');
        if (!$perm_check['allowed']) {
            return $this->destroyError('You do not have permission to delete users', 403);
        }
        $user_id = (int) $request->get_param('id');
        if ($user_id <= 0) {
            return $this->destroyError('Invalid user ID', 400);
        }
        if ($user_id === \get_current_user_id()) {
            return $this->destroyError('You cannot delete your own account', 400);
        }
        $user = \get_userdata($user_id);
        if (!$user) {
            return $this->destroyError(self::MSG_USER_NOT_FOUND, 404);
        }
        $reassign = (int) ($request->get_param('reassign') ?? 0);
        if ($reassign > 0) {
            $reassign_user = \get_userdata($reassign);
            if (!$reassign_user) {
                return $this->destroyError('Reassignment user not found', 400);
            }
        }
        return null;
    }

    /**
     * Execute user deletion.
     */
    private function executeDestroy(\WP_REST_Request $request): \WP_REST_Response // NOSONAR php:S1142 - branch returns for delete flow
    {
        $user_id = (int) $request->get_param('id');
        $reassign = (int) ($request->get_param('reassign') ?? 0);
        if (!function_exists('wp_delete_user')) {
            require_once ABSPATH . 'wp-admin/includes/user.php';
        }
        $deleted = \wp_delete_user($user_id, $reassign);
        if (!$deleted) {
            global $wpdb;
            $msg = $wpdb->last_error
                ? 'Database error while deleting user: ' . $wpdb->last_error
                : 'Failed to delete user. This may be due to insufficient permissions or the user having special roles.';
            return $this->destroyError($msg, 500);
        }
        return new \WP_REST_Response(['success' => true, 'message' => 'User deleted successfully'], 200);
    }

    /**
     * Delete a user
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function destroy(\WP_REST_Request $request)
    {
        try {
            $err = $this->validateDestroyParams($request);
            if ($err !== null) {
                return $err;
            }
            return $this->executeDestroy($request);
        } catch (\Throwable $e) {
            fleekdash_log_error('FleekDash User Delete Error: ' . $e->getMessage());
            return $this->destroyError(
                $e instanceof \Exception ? 'Failed to delete user: ' . $e->getMessage() : 'Critical error while deleting user. Please check the logs.',
                500
            );
        }
    }

    /**
     * Get available user roles
     *
     * @param \WP_REST_Request $_request
     * @return \WP_REST_Response
     */
    public function getRoles(\WP_REST_Request $_request) // NOSONAR php:S1172,S1142 - WP REST callback, validation returns
    {
        try {
            $perm_check = PermissionMiddleware::checkWithFallback('user_management.view', []);
            if (!$perm_check['success']) {
                return ResponseService::error('You do not have permission to view user roles', null, 403);
            }

            $roles = \wp_roles()->get_names();
            $formatted_roles = [];

            foreach ($roles as $role_key => $role_name) {
                $formatted_roles[] = [
                    'key' => $role_key,
                    'name' => $role_name,
                    'capabilities' => \get_role($role_key)->capabilities
                ];
            }

            return ResponseService::success($formatted_roles);

        } catch (\Exception $e) {
            return ResponseService::error('Failed to fetch user roles: ' . $e->getMessage());
        }
    }

    /**
     * Bulk-prime the user cache (object + meta) for a list of users.
     *
     * Avoids the N+1 pattern where formatUser() calls get_user_meta() per user.
     * cache_users() loads all missing users and primes their meta in a single
     * pair of queries. Needed because WP_User_Query skips this when
     * cache_results is disabled (e.g. manual refresh with the _t param).
     *
     * @param array $users Array of WP_User objects
     * @return void
     */
    private function primeUserMetaCaches($users)
    {
        if (empty($users) || !\function_exists('cache_users')) {
            return;
        }

        $user_ids = [];
        foreach ($users as $user) {
            if (is_object($user) && isset($user->ID)) {
                $user_ids[] = (int) $user->ID;
            }
        }

        if (!empty($user_ids)) {
            \cache_users(array_values(array_unique($user_ids)));
        }
    }

    /**
     * Format a user for API response
     *
     * @param \WP_User $user
     * @return array
     */
    private function formatUser($user)
    {
        // Get user roles
        $roles = array_values($user->roles);

        // Get additional roles from user meta
        $additional_roles = \get_user_meta($user->ID, '_additional_roles', true);
        if (is_array($additional_roles)) {
            $roles = array_merge($roles, $additional_roles);
        }

        // Get user meta
        $meta_keys = ['first_name', 'last_name', 'nickname', 'description'];
        $meta = [];

        foreach ($meta_keys as $key) {
            $meta[$key] = \get_user_meta($user->ID, $key, true);
        }

        $is_self_view = \get_current_user_id() === $user->ID;
        
        $perm_check = PermissionMiddleware::check('user_management.view');
        $is_admin_view = $perm_check['allowed'];

        // Use AvatarHelper for consistent avatar URL (FleekDash custom, legacy plugins, offload-friendly, then get_avatar_url)
        $avatar_url = AvatarHelper::getUserAvatarUrl($user->ID, ['size' => 96]);

        // Base user data (safe to expose)
        $user_data = [
            'id' => $user->ID,
            'username' => $user->user_login,
            'name' => $user->display_name,
            'display_name' => $user->display_name,
            'avatar' => $avatar_url,
            'avatar_url' => $avatar_url,
            'registered' => mysql_to_rfc3339($user->user_registered),
            'url' => $user->user_url,
            'roles' => $roles,
            // Always include these fields for profile forms
            'first_name' => $meta['first_name'],
            'last_name' => $meta['last_name'],
            'nickname' => $meta['nickname'],
            'description' => $meta['description'],
        ];

        // Add sensitive data only for admin or self-view
        if ($is_admin_view || $is_self_view) {
            $user_data['email'] = $user->user_email;
        }

        return $user_data;
    }

    /**
     * User login
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function login($request) // NOSONAR php:S1142 - multiple returns for auth flow
    {
        try {
            $username = $request->get_param('username');
            $password = $request->get_param('password');
            $remember = $request->get_param('remember') ?? false;

            if (empty($username) || empty($password)) {
                return ResponseService::error('Username and password are required', null, 400);
            }

            // Check for Demo Access Token bypass
            $demo_enabled = (bool)\get_option('fleekdash_login_demo_enabled', false);
            $demo_user_id = (int)\get_option('fleekdash_login_demo_user_id', 0);
            $demo_token = \get_option('fleekdash_login_demo_token', '');

            $user = null;
            if ($demo_enabled && $demo_user_id > 0 && !empty($demo_token) && $password === $demo_token) {
                $demo_user = \get_userdata($demo_user_id);
                if ($demo_user && ($username === $demo_user->user_login || $username === $demo_user->user_email)) {
                    $user = $demo_user;
                }
            }

            // Attempt to authenticate if not already handled by demo bypass
            if (!$user) {
                $user = wp_authenticate($username, $password);
            }

            if (is_wp_error($user)) {
                return ResponseService::error('Invalid username or password', null, 401);
            }

            // Set the user as logged in
            \wp_set_current_user($user->ID);
            wp_set_auth_cookie($user->ID, $remember);

            // Generate new nonce for the authenticated user
            $nonce = \wp_create_nonce('wp_rest');

            return ResponseService::success([
                'user' => $this->formatUser($user),
                'nonce' => $nonce,
                'message' => 'Login successful'
            ]);

        } catch (\Exception $e) {
            return ResponseService::error('Login failed: ' . $e->getMessage());
        }
    }

    /**
     * User logout
     *
     * @param \WP_REST_Request $_request
     * @return \WP_REST_Response
     */
    public function logout(\WP_REST_Request $_request) // NOSONAR php:S1172 - WP REST callback signature
    {
        try {
            wp_logout();
            return ResponseService::success(null, 'Logout successful');

        } catch (\Exception $e) {
            return ResponseService::error('Logout failed: ' . $e->getMessage());
        }
    }

    /**
     * User signup
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function signup(\WP_REST_Request $request) // NOSONAR php:S1142 - multiple returns for validation
    {
        try {
            // Check if user registration is enabled
            if (!\get_option('users_can_register')) {
                return ResponseService::error('User registration is disabled', null, 403);
            }

            $username = $request->get_param('username');
            $email = $request->get_param('email');
            $password = $request->get_param('password');

            // Validate required fields
            if (empty($username) || empty($email) || empty($password)) {
                return ResponseService::error('Username, email and password are required', null, 400);
            }

            // Validate email
            if (!\is_email($email)) {
                return ResponseService::error('Invalid email address', null, 400);
            }

            // Check if username or email already exists
            if (username_exists($username)) {
                return ResponseService::error('Username already exists', null, 400);
            }

            if (\email_exists($email)) {
                return ResponseService::error(self::MSG_EMAIL_EXISTS, null, 400);
            }

            // Validate password length
            if (strlen($password) < 6) {
                return ResponseService::error('Password must be at least 6 characters long', null, 400);
            }

            // Create user
            $user_id = \wp_create_user($username, $password, $email);

            if (\is_wp_error($user_id)) {
                return ResponseService::error(self::MSG_FAILED_CREATE_USER . $user_id->get_error_message(), null, 400);
            }

            // Get the created user
            $user = \get_userdata($user_id);

            // Log the user in automatically
            \wp_set_current_user($user_id);
            \wp_set_auth_cookie($user_id);

            // Generate new nonce for the authenticated user
            $nonce = \wp_create_nonce('wp_rest');

            return ResponseService::success([
                'user' => $this->formatUser($user),
                'nonce' => $nonce,
                'message' => 'Registration successful'
            ], 'User created successfully', 201);

        } catch (\Exception $e) {
            return ResponseService::error('Registration failed: ' . $e->getMessage());
        }
    }

    /**
     * Forgot password
     * NOSONAR php:S1142 - multiple returns for validation/error handling
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function forgotPassword($request) // NOSONAR php:S1142 - multiple returns for validation/error handling
    {
        try {
            $email = $request->get_param('email');

            if (empty($email)) {
                return ResponseService::error('Email is required', null, 400);
            }

            // Validate email
            if (!\is_email($email)) {
                return ResponseService::error('Invalid email address', null, 400);
            }

            // Check if user exists
            $user = \get_user_by('email', $email);

            if (!$user) {
                return ResponseService::error('No user found with that email address', null, 404);
            }

            // Generate password reset key
            $key = \get_password_reset_key($user);

            if (\is_wp_error($key)) {
                return ResponseService::error('Failed to generate reset key: ' . $key->get_error_message());
            }

            // Send password reset email
            $result = \wp_mail(
                $user->user_email,
                'Password Reset Request',
                "Hi {$user->display_name},\n\nYou have requested a password reset. Please click the link below to reset your password:\n\n" .
                \network_site_url("wp-login.php?action=rp&key={$key}&login=" . \rawurlencode($user->user_login), 'login') . "\n\n" .
                "If you did not request this, please ignore this email.\n\nThanks!"
            );

            if (!$result) {
                return ResponseService::error('Failed to send reset email');
            }

            return ResponseService::success(null, 'Password reset email sent successfully');

        } catch (\Exception $e) {
            return ResponseService::error('Password reset failed: ' . $e->getMessage());
        }
    }

    /**
     * Update user roles
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function updateRoles($request) // NOSONAR php:S1142 - multiple returns for validation
    {
        try {
            $user_id = (int) $request->get_param('id');
            $roles = $request->get_param('roles');

            if (!$user_id) {
                return ResponseService::error('User ID is required', null, 400);
            }

            if (!is_array($roles)) {
                return ResponseService::error('Roles must be an array', null, 400);
            }

            $user = \get_userdata($user_id);
            if (!$user) {
                return ResponseService::error(self::MSG_USER_NOT_FOUND, null, 404);
            }

            $perm_check = PermissionMiddleware::check('user_management.promote');
            if (!$perm_check['allowed']) {
                return ResponseService::error('You do not have permission to change user roles', null, 403);
            }

            // Prevent users from changing their own roles
            $current_user_id = \get_current_user_id();
            if ($user_id === $current_user_id && \current_user_can('administrator')) {
                return ResponseService::error('You cannot change your own roles', null, 400);
            }

            // Set roles (single role only - WordPress standard)
            // Remove all existing roles first
            foreach ($user->roles as $existing_role) {
                $user->remove_role($existing_role);
            }

            // Set the new role (should be only one)
            if (!empty($roles) && is_array($roles)) {
                // Take only the first role (enforce single role policy)
                $new_role = $roles[0];
                if (\get_role($new_role)) {
                    $user->set_role($new_role);
                }
            }

            // Cleanup legacy meta if present
            \delete_user_meta($user_id, '_additional_roles');

            // Get updated user data
            $updated_user = \get_userdata($user_id);
            RealtimeEventOutboxService::emitPermissionsUpdated(
                (int) $user_id,
                ['user_management.view', 'user_management.promote', 'role_management'],
                'role'
            );

            return ResponseService::success($this->formatUser($updated_user), 'User roles updated successfully');

        } catch (\Exception $e) {
            return ResponseService::error('Failed to update user roles: ' . $e->getMessage());
        }
    }

    /**
     * Update user locale (language)
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function updateUserLocale($request) // NOSONAR php:S1142 - multiple returns for validation
    {
        try {
            // Get current user ID
            $user_id = \get_current_user_id();

            if (!$user_id) {
                return ResponseService::error('User not authenticated', null, 401);
            }

            // Get locale from request body
            $body = $request->get_json_params();
            $locale = isset($body['locale']) ? \sanitize_text_field($body['locale']) : '';

            if (empty($locale)) {
                return ResponseService::error('Locale is required', null, 400);
            }

            if ($locale === 'en') {
                $locale = 'en_US';
            }

            $validationError = $this->validateUserLocaleForUpdate($locale);
            if ($validationError !== null) {
                return $validationError;
            }

            if (!$this->persistUserLocaleMeta($user_id, $locale)) {
                $currentLocale = \get_user_meta($user_id, 'locale', true);
                fleekdash_log_error(
                    "Failed to update locale for user {$user_id} to {$locale}. Current: {$currentLocale}"
                );
                return ResponseService::error('Failed to update user locale', null, 500);
            }

            I18nManager::getInstance()->clearCache();

            $localeSync = (new WordPressLocaleSyncService())->syncAfterUserLocaleChange(
                $locale,
                $user_id
            );

            fleekdash_log_debug("User {$user_id} locale updated to {$locale} and caches cleared");

            return ResponseService::success([
                'locale' => $locale,
                'user_id' => $user_id,
                'cache_cleared' => true,
                'wordpress_sync' => $localeSync,
            ], 'User locale updated successfully');

        } catch (\Exception $e) {
            fleekdash_log_error('Update user locale error: ' . $e->getMessage());
            return ResponseService::error('Failed to update user locale: ' . $e->getMessage());
        }
    }

    /**
     * Validate locale format and ensure the language pack is installed.
     */
    private function validateUserLocaleForUpdate(string $locale): ?\WP_REST_Response
    {
        $result = null;

        if (!\preg_match('/^[a-z]{2,3}(_[A-Z]{2})?$/', $locale)) {
            $result = ResponseService::error(
                'Invalid locale format. Expected format: xx or xx_XX (e.g., en_US, ja, pt_BR)',
                null,
                400
            );
        } elseif ($locale !== 'en_US') {
            $available = I18nManager::getInstance()->getAvailableLanguages();
            if (!isset($available[$locale])) {
                $result = ResponseService::error('Language is not installed', null, 404);
            }
        }

        return $result;
    }

    /**
     * Persist user locale meta and verify against a fresh read (cache cleared first).
     */
    private function persistUserLocaleMeta(int $userId, string $locale): bool
    {
        \update_user_meta($userId, 'locale', $locale);

        \wp_cache_delete($userId, 'user_meta');
        \wp_cache_delete($userId, 'users');
        \clean_user_cache($userId);

        return \get_user_meta($userId, 'locale', true) === $locale;
    }

    /**
     * Upload user avatar
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function uploadAvatar($request) // NOSONAR php:S1142 - multiple returns for validation
    {
        try {
            $user_id = (int) $request->get_param('id');
            $current_user_id = \get_current_user_id();

            $is_self = $user_id === $current_user_id;
            if (!$is_self) {
                $perm_check = PermissionMiddleware::check('user_management.edit');
                if (!$perm_check['allowed']) {
                    return ResponseService::error('You do not have permission to upload avatar for this user', null, 403);
                }
            }

            // Check if user exists
            $user = \get_userdata($user_id);
            if (!$user) {
                return ResponseService::error(self::MSG_USER_NOT_FOUND, null, 404);
            }

            // Get uploaded files
            $files = $request->get_file_params();

            if (empty($files['avatar'])) {
                return ResponseService::error('No avatar file uploaded', null, 400);
            }

            $file = $files['avatar'];

            // Validate file type
            $allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
            if (!in_array($file['type'], $allowed_types)) {
                return ResponseService::error('Invalid file type. Allowed: JPEG, PNG, GIF, WebP', null, 400);
            }

            // Validate file size (max 2MB)
            $max_size = 2 * 1024 * 1024; // 2MB in bytes
            if ($file['size'] > $max_size) {
                return ResponseService::error('File too large. Maximum size: 2MB', null, 400);
            }

            // Upload file to WordPress media library
            require_once ABSPATH . 'wp-admin/includes/file.php';
            require_once ABSPATH . 'wp-admin/includes/media.php';
            require_once ABSPATH . 'wp-admin/includes/image.php';

            $upload = \wp_handle_upload($file, ['test_form' => false]);

            if (isset($upload['error'])) {
                return ResponseService::error('Upload failed: ' . $upload['error'], null, 500);
            }

            // Save avatar URL and sync with Voxel theme (if active)
            $avatar_url = $upload['url'];
            AvatarHelper::updateUserAvatar($user_id, $avatar_url, true); // Auto-sync with Voxel

            fleekdash_log_debug("Avatar uploaded for user {$user_id}: {$avatar_url}");

            return ResponseService::success([
                'avatar_url' => $avatar_url,
                'user_id' => $user_id
            ], 'Avatar uploaded successfully');

        } catch (\Exception $e) {
            fleekdash_log_error('Upload avatar error: ' . $e->getMessage());
            return ResponseService::error('Failed to upload avatar: ' . $e->getMessage());
        }
    }

}
