<?php

namespace WPUF\UserDirectory;

use WP_User;

/**
 * ShortCode handler for User Directory
 *
 * @since 4.2.0
 */
class ShortCode {

    /**
     * Assets handler instance
     *
     * @since 4.2.0
     * @var Assets
     */
    private $assets;

    /**
     * Constructor
     *
     * @since 4.2.0
     */
    public function __construct() {
        $this->assets = new Assets();
        $this->register_hooks();
    }

    /**
     * Register WordPress hooks
     *
     * @since 4.2.0
     *
     * @return void
     */
    public function register_hooks() {
        add_shortcode( 'wpuf_user_listing', [ $this, 'render_shortcode' ] );
        add_shortcode( 'wpuf_user_listing_id', [ $this, 'render_shortcode_with_id' ] );
        add_filter( 'document_title_parts', [ $this, 'modify_profile_page_title' ], 10, 1 );
        add_filter( 'wp_title', [ $this, 'modify_profile_page_title_legacy' ], 10, 2 );
    }

    /**
     * Render shortcode output
     *
     * @since 4.2.0
     *
     * @param array $atts Shortcode attributes
     *
     * @return string HTML output
     */
    public function render_shortcode( $atts ) {
        // If ID is provided (regardless of URL parameters), load settings from database
        if ( isset( $atts['id'] ) ) {
            return $this->render_from_stored_settings( $atts['id'] );
        }

        // For backward compatibility - old shortcodes without ID should use legacy settings
        return $this->render_legacy_shortcode( $atts );
    }

    /**
     * Render shortcode with ID parameter for new format
     *
     * @since 4.2.0
     *
     * @param array $atts Shortcode attributes - expects ID as the value
     *
     * @return string HTML output
     */
    public function render_shortcode_with_id( $atts ) {
        // For [wpuf_user_listing_id="123"], the ID is the value directly
        if ( is_array( $atts ) && ! empty( $atts ) ) {
            $directory_id = reset( $atts ); // Get the first value
            return $this->render_from_stored_settings( $directory_id );
        }

        return '';
    }

    /**
     * Render legacy shortcode without ID (backward compatibility)
     *
     * @since 4.2.0
     *
     * @param array $atts Shortcode attributes
     *
     * @return string HTML output
     */
    private function render_legacy_shortcode( $atts ) {
        // Get legacy settings from wpuf_userlisting option
        $legacy_settings = get_option( 'wpuf_userlisting', [] );

        // If no legacy settings exist, use new system with defaults
        if ( empty( $legacy_settings ) ) {
            return $this->user_lists( $atts, true ); // true = legacy mode with defaults
        }

        // Convert legacy settings to new format
        $converted_atts = $this->convert_legacy_settings_to_atts( $legacy_settings, $atts );

        // Render using converted attributes
        return $this->user_lists( $converted_atts, true ); // true = legacy mode
    }

    /**
     * Convert legacy wpuf_userlisting settings to shortcode attributes
     *
     * @since 4.2.0
     *
     * @param array $legacy_settings Legacy settings from wpuf_userlisting option
     * @param array $atts Original shortcode attributes
     *
     * @return array Converted attributes
     */
    private function convert_legacy_settings_to_atts( $legacy_settings, $atts ) {
        // Start with empty array, we'll merge with $atts at the end to preserve overrides
        $converted = [];

        // Extract settings section
        $settings = isset( $legacy_settings['settings'] ) ? $legacy_settings['settings'] : [];

        // Map legacy settings to new attributes
        if ( ! empty( $settings['max_item'] ) ) {
            $converted['max_item'] = $settings['max_item'];
        }

        if ( ! empty( $settings['max_item_per_page'] ) ) {
            $converted['per_page'] = $settings['max_item_per_page'];
        }

        if ( ! empty( $settings['show_search'] ) ) {
            $converted['enable_search'] = $settings['show_search'] === 'yes' ? 'yes' : 'no';
        }

        if ( ! empty( $settings['avatar_size'] ) ) {
            $converted['avatar_size'] = $settings['avatar_size'];
        }

        // Get columns from legacy fields marked with in_table
        if ( ! empty( $legacy_settings['fields'] ) ) {
            $columns = [];
            $meta_fields = [];

            foreach ( $legacy_settings['fields'] as $field ) {
                if ( $field['type'] === 'meta' && isset( $field['in_table'] ) && $field['in_table'] === 'yes' ) {
                    $meta_key = $field['meta'];
                    $columns[] = $meta_key;
                    $meta_fields[$meta_key] = $field['label'];
                }
            }

            if ( ! empty( $columns ) ) {
                $converted['columns'] = implode( ',', $columns );
            }

            // Store meta fields for later use
            $converted['legacy_meta_fields'] = $meta_fields;
        }

        // Get profile tabs
        if ( ! empty( $legacy_settings['profile_tabs'] ) ) {
            $tabs = [];
            foreach ( $legacy_settings['profile_tabs'] as $tab_id => $tab ) {
                if ( ! empty( $tab['show_tab'] ) ) {
                    $tabs[] = $tab_id;
                }
            }
            if ( ! empty( $tabs ) ) {
                $converted['default_tabs'] = implode( ',', $tabs );
            }
        }

        // Get directory listing layout from wpuf settings (legacy location)
        $user_listing_template = wpuf_get_option( 'user_listing_template', 'user_directory', 'list' );

        // Map legacy directory layout values to new format
        $directory_layout_map = [
            'list'  => 'layout-1',  // Table layout
            'list1' => 'layout-2',  // Square grid 2
            'list2' => 'layout-3',  // Circle thumbnail grid 3
            'list3' => 'layout-4',  // Square thumbnail grid 3
            'list4' => 'layout-5',  // Circle thumbnail grid 4
            'list5' => 'layout-6',  // Square thumbnail grid 4
        ];

        if ( isset( $directory_layout_map[ $user_listing_template ] ) ) {
            $converted['directory_layout'] = $directory_layout_map[ $user_listing_template ];
        } else {
            // Default to layout-1 if not recognized
            $converted['directory_layout'] = 'layout-1';
        }

        // Get profile layout from wpuf_general settings (legacy location)
        $profile_header_template = wpuf_get_option( 'profile_header_template', 'user_directory', 'layout' );

        // Map legacy profile layout values to new format
        $profile_layout_map = [
            'layout'  => 'layout-1',
            'layout1' => 'layout-2',
            'layout2' => 'layout-3',
        ];

        if ( isset( $profile_layout_map[ $profile_header_template ] ) ) {
            $converted['profile_layout'] = $profile_layout_map[ $profile_header_template ];
        } else {
            // Default to layout-1 if not recognized
            $converted['profile_layout'] = 'layout-1';
        }

        // Get profile permalink base from legacy settings
        $profile_permalink_base = wpuf_get_option( 'profile_permalink_base', 'user_directory', 'username' );

        // The new system uses 'username' or 'user_id', legacy uses 'username' or 'user_id' too
        $converted['profile_permalink'] = $profile_permalink_base;

        // Get other legacy settings that might be useful
        $converted['avatar_size'] = wpuf_get_option( 'avatar_size', 'user_directory', '120' );
        $converted['enable_search'] = wpuf_get_option( 'show_search', 'user_directory', 'yes' ) === 'yes' ? 'yes' : 'no';

        // Get gallery image size from legacy settings
        $pro_img_size = wpuf_get_option( 'pro_img_size', 'user_directory', '78' );
        // Map to standard WordPress image sizes if numeric
        if ( is_numeric( $pro_img_size ) ) {
            // Convert numeric size to closest WordPress size
            $size_int = intval( $pro_img_size );
            if ( $size_int <= 150 ) {
                $converted['gallery_img_size'] = 'thumbnail';
            } elseif ( $size_int <= 300 ) {
                $converted['gallery_img_size'] = 'medium';
            } else {
                $converted['gallery_img_size'] = 'large';
            }
        } else {
            $converted['gallery_img_size'] = $pro_img_size;
        }

        // Add legacy flag for special handling
        $converted['is_legacy'] = true;

        // Merge with provided attributes, giving precedence to explicitly set shortcode attributes
        // This ensures that if someone has [wpuf_user_listing profile_layout="layout-3"], it overrides legacy
        $final_atts = array_merge( $converted, $atts );

        return $final_atts;
    }

    /**
     * Render shortcode using stored directory settings
     *
     * @since 4.2.0
     *
     * @param string $directory_id Directory post ID
     *
     * @return string HTML output
     */
    private function render_from_stored_settings( $directory_id ) {
        $directory_id = sanitize_text_field( $directory_id );

        // If no ID provided, return empty
        if ( empty( $directory_id ) ) {
            return '';
        }

        // Get directory settings from database
        $directory_post = get_post( $directory_id );
        if ( ! $directory_post || 'wpuf_user_listing' !== $directory_post->post_type || 'publish' !== $directory_post->post_status ) {
            return '';
        }

        // Parse stored settings
        $stored_settings = [];
        if ( ! empty( $directory_post->post_content ) ) {
            $stored_settings = json_decode( $directory_post->post_content, true ) ?: [];
        }

        // Map stored settings to shortcode attributes
        // Handle field name mapping between frontend and backend
        // Get tabs from settings - only include enabled tabs
        if ( isset( $stored_settings['default_tabs'] ) ) {
            $default_tabs = $stored_settings['default_tabs'];
        } elseif ( isset( $stored_settings['profile_tabs'] ) ) {
            // profile_tabs contains only the enabled tabs array
            $default_tabs = $stored_settings['profile_tabs'];
        } else {
            // No fallback - if no tabs selected, should be empty
            $default_tabs = '';
        }
        $gallery_img_size = $stored_settings['gallery_img_size'] ?? $stored_settings['profile_size'] ?? 'thumbnail';
        $profile_permalink = $stored_settings['profile_permalink'] ?? $stored_settings['profile_base'] ?? 'username';
        $per_page = $stored_settings['per_page'] ?? $stored_settings['max_item_per_page'] ?? 10;

        // Convert array to comma-separated string if needed
        if ( is_array( $default_tabs ) ) {
            $default_tabs = implode(',', $default_tabs);
        }

        // Convert array roles to comma-separated string if needed
        $roles = $stored_settings['roles'] ?? 'all';
        if ( is_array( $roles ) ) {
            $roles = implode(',', $roles);
        }

        // Check if directory_layout is in URL parameters (for pagination/filtering)
        $url_layout = isset( $_GET['directory_layout'] ) ? sanitize_text_field( $_GET['directory_layout'] ) : '';

        // Check multiple possible keys for layout in stored settings
        $stored_layout = $stored_settings['directory_layout']
            ?? $stored_settings['layout']
            ?? $stored_settings['template']
            ?? 'layout-1';

        $full_atts = [
            'id' => $directory_id,
            'directory_id' => $directory_id, // Add directory_id for template compatibility
            'roles' => $roles,
            'exclude_users' => $this->extract_user_ids_from_excluded_users( $stored_settings['excluded_users'] ?? [] ),
            'per_page' => $per_page,
            'max_item' => $stored_settings['max_item'] ?? null, // Add max_item for total users limit
            'directory_layout' => $url_layout ?: $stored_layout,
            'profile_layout' => $stored_settings['profile_layout'] ?? 'layout-1',
            'default_tabs' => $default_tabs,
            'gallery_img_size' => $gallery_img_size,
            'avatar_size' => $stored_settings['avatar_size'] ?? '32',
            'profile_permalink' => $profile_permalink,
            'orderby' => $this->normalize_orderby_field( $stored_settings['orderby'] ?? 'id' ),
            'order' => $stored_settings['order'] ?? 'desc',
            'enable_search' => isset($stored_settings['enable_search']) ? ($stored_settings['enable_search'] ? 'yes' : 'no') : 'yes',
            'enable_frontend_sorting' => $stored_settings['enable_frontend_sorting'] ?? 'yes',
            'search_placeholder' => $stored_settings['search_placeholder'] ?? '',
            'searchable_fields' => is_array($stored_settings['searchable_fields'] ?? null) ? implode(',', $stored_settings['searchable_fields']) : ($stored_settings['searchable_fields'] ?? ''),
            'show_avatar_in_table' => $stored_settings['show_avatar_in_table'] ?? true,
            'columns' => is_array($stored_settings['columns'] ?? null) ? implode(',', $stored_settings['columns']) : ($stored_settings['columns'] ?? ''),
            'social_fields' => $stored_settings['social_fields'] ?? [],
        ];

        // Use the existing user_lists method with full attributes
        return $this->user_lists( $full_atts );
    }


    /**
     * Handle user listing shortcode
     *
     * @since 4.2.0
     *
     * @param array $atts Shortcode attributes
     * @param bool $is_legacy Whether this is a legacy shortcode without ID
     *
     * @return string HTML output
     */
    public function user_lists( $atts, $is_legacy = false ) {
        // Parse and sanitize attributes
        $attributes = $this->parse_attributes( $atts, $is_legacy );

        // Check if we're viewing a single profile
        $profile_user = $this->get_profile_user( $attributes );

        if ( $profile_user ) {
            return $this->render_profile_view( $profile_user, $attributes );
        }

        // Generate unique instance ID for this shortcode
        $instance_id = 'shortcode_' . uniqid();

        // Prepare template data
        $template_data = $this->prepare_template_data( $attributes, $instance_id );

        // Determine layout template
        $layout_template = $this->get_layout_template( $attributes['directory_layout'] );

        // Start output buffering
        ob_start();

        // Add action hook before directory output
        do_action( 'wpuf_user_directory_before_output', $attributes );

        // Load the template from shortcodes directory
        wpuf_load_pro_template( $layout_template . '.php', $template_data, WPUF_UD_TEMPLATES . '/shortcodes/directory/' );

        // Add action hook after directory output
        do_action( 'wpuf_user_directory_after_output', $attributes );

        return ob_get_clean();
    }    /**
     * Parse and sanitize shortcode attributes
     *
     * @since 4.2.0
     *
     * @param array $atts Raw shortcode attributes
     * @param bool $is_legacy Whether this is a legacy shortcode without ID
     *
     * @return array Parsed and sanitized attributes
     */
    private function parse_attributes( $atts, $is_legacy = false ) {
        $defaults = [
            'id'                => '',
            'directory_id'      => '', // Add directory_id for template compatibility
            'role'              => 'all',
            'roles'             => 'all', // Alternative to 'role' for consistency
            'exclude_users'     => [],
            'per_page'          => 10,
            'max_item'          => null, // Maximum number of users to display
            'directory_layout'  => 'layout-1',
            'profile_layout'    => 'layout-1',
            'default_tabs'      => $is_legacy ? 'about,posts,comments' : '', // Legacy gets defaults, new gets empty
            'gallery_img_size'  => 'thumbnail',
            'avatar_size'       => '32',
            'profile_permalink' => 'username',
            'orderby'           => 'id',
            'order'             => 'desc',
            'enable_search'     => 'yes',
            'enable_frontend_sorting' => 'yes',
            'search_placeholder' => '',
            'searchable_fields' => '',
            'columns'           => '', // Will be populated from legacy settings if needed
            'social_fields'     => [],
            'show_avatar_in_table' => true,  // Default to true
        ];

        $attributes = shortcode_atts( $defaults, $atts, 'wpuf_user_listing' );

        // Handle role/roles consolidation - 'roles' takes precedence over 'role'
        if (!empty($attributes['roles']) && $attributes['roles'] !== 'all') {
            $attributes['role'] = $attributes['roles'];
        }

        // Sanitize attributes
        $attributes['id']                = sanitize_text_field( $attributes['id'] );
        $attributes['directory_id']      = sanitize_text_field( $attributes['directory_id'] );
        $attributes['role']              = sanitize_text_field( $attributes['role'] );
        $attributes['roles']             = sanitize_text_field( $attributes['roles'] );
        $attributes['per_page']          = absint( $attributes['per_page'] );
        $attributes['max_item']          = $attributes['max_item'] !== null ? intval( $attributes['max_item'] ) : null;
        $attributes['directory_layout']  = sanitize_text_field( $attributes['directory_layout'] );
        $attributes['profile_layout']    = sanitize_text_field( $attributes['profile_layout'] );
        $attributes['default_tabs']      = sanitize_text_field( $attributes['default_tabs'] );
        $attributes['gallery_img_size']  = sanitize_text_field( $attributes['gallery_img_size'] );
        $attributes['avatar_size']       = absint( $attributes['avatar_size'] );
        $attributes['profile_permalink'] = sanitize_text_field( $attributes['profile_permalink'] );
        $attributes['orderby']           = sanitize_key( $attributes['orderby'] );
        $attributes['order']             = sanitize_text_field( $attributes['order'] );
        $attributes['search_placeholder'] = sanitize_text_field( $attributes['search_placeholder'] );
        $attributes['searchable_fields'] = sanitize_text_field( $attributes['searchable_fields'] );
        $attributes['columns']           = sanitize_text_field( $attributes['columns'] );

        // Sanitize social_fields array
        if ( is_array( $attributes['social_fields'] ) ) {
            $attributes['social_fields'] = array_map( 'sanitize_text_field', $attributes['social_fields'] );
        } else {
            $attributes['social_fields'] = [];
        }

        // Sanitize exclude_users array
        if ( is_array( $attributes['exclude_users'] ) ) {
            $attributes['exclude_users'] = array_map( 'intval', $attributes['exclude_users'] );
            $attributes['exclude_users'] = array_filter( $attributes['exclude_users'] ); // Remove zeros
        } else {
            $attributes['exclude_users'] = [];
        }

        // Validate specific values
        $attributes['order'] = in_array( strtolower( $attributes['order'] ), [ 'asc', 'desc' ], true )
            ? strtolower( $attributes['order'] )
            : 'desc';

        // Get valid orderby fields (core + enabled meta fields)
        $valid_orderby_fields = $this->get_valid_orderby_fields( $attributes['id'] ?? null );
        $attributes['orderby'] = in_array( $attributes['orderby'], $valid_orderby_fields, true )
            ? $attributes['orderby']
            : 'id';

        $attributes['profile_permalink'] = in_array( $attributes['profile_permalink'], [ 'username', 'user_id' ], true )
            ? $attributes['profile_permalink']
            : 'username';

        // Ensure minimum values
        $attributes['per_page'] = max( 1, $attributes['per_page'] );
        // Don't set a minimum for avatar_size, let templates decide their defaults
        // $attributes['avatar_size'] = max( 16, $attributes['avatar_size'] );

        return $attributes;
    }

    /**
     * Prepare template data for rendering
     *
     * @since 4.2.0
     *
     * @param array $attributes Parsed shortcode attributes
     * @param string $instance_id Unique instance ID
     *
     * @return array Template data
     */
    private function prepare_template_data( $attributes, $instance_id ) {
        // Get current page for pagination
        $current_page = $this->get_current_page();
        $offset = ( $current_page - 1 ) * $attributes['per_page'];

        // Prepare user query filters
        $filters = [
            'roles'         => $this->parse_roles( $attributes['role'] ),
            'exclude_users' => $attributes['exclude_users'],
            'per_page'      => $attributes['per_page'],
            'max_item'      => $attributes['max_item'] ?? null, // Add max_item for total users limit
            'offset'        => $offset,
            'orderby'       => $attributes['orderby'],
            'order'         => $attributes['order'],
            'directory_id'  => $attributes['id'] ?? null, // Pass directory ID for meta field detection
        ];

        // Add search functionality
        if ( ! empty( $_GET['search'] ) ) {
            $filters['search'] = sanitize_text_field( $_GET['search'] );

            // Handle search_by parameter for single column search - synced with API (User_Listing.php)
            $search_by = ! empty( $_GET['search_by'] ) ? sanitize_text_field( $_GET['search_by'] ) : '';

            if ( ! empty( $search_by ) ) {
                // Core fields that exist in wp_users table and can be searched via search_columns
                $core_fields = [ 'user_login', 'user_email', 'display_name', 'user_url', 'user_nicename' ];

                if ( in_array( $search_by, $core_fields, true ) ) {
                    // Use core field search
                    $filters['searchable_fields'] = [ $search_by ];
                } else {
                    // Use meta field search
                    $filters['search_meta_field'] = sanitize_key( $search_by );
                }
            } elseif ( ! empty( $attributes['searchable_fields'] ) ) {
                // Default search in specified fields
                $filters['searchable_fields'] = $attributes['searchable_fields'];
            } else {
                // Default search in all core fields
                $filters['searchable_fields'] = [ 'user_login', 'user_email', 'display_name' ];
            }
        }

        // Get users
        $user_query = function_exists( 'wpuf_ud_get_users' ) ? wpuf_ud_get_users( $filters ) : [ 'users' => [], 'total' => 0 ];
        $users = $user_query['users'];
        $total = $user_query['total'];

        // Calculate pagination
        $total_pages = $attributes['per_page'] > 0 ? (int) ceil( $total / $attributes['per_page'] ) : 1;

        // Prepare columns from attributes or use defaults
        if ( ! empty( $attributes['columns'] ) ) {
            // If columns is a string (comma-separated), convert to array
            if ( is_string( $attributes['columns'] ) ) {
                $columns = array_map( 'trim', explode( ',', $attributes['columns'] ) );
            } else {
                $columns = $attributes['columns'];
            }

            // Check if we have the old default columns (user_login, display_name)
            // and no custom meta columns - then replace with new defaults
            $basic_fields = ['avatar', 'name', 'email', 'display_name', 'user_email', 'user_login', 'role', 'posts', 'joined', 'website', 'user_url'];
            $has_custom_meta = false;
            foreach ( $columns as $col ) {
                if ( !in_array( $col, $basic_fields ) ) {
                    $has_custom_meta = true;
                    break;
                }
            }

            // If we only have user_login and display_name (old defaults), replace with new defaults
            if ( !$has_custom_meta && in_array( 'user_login', $columns ) && in_array( 'display_name', $columns ) && count( $columns ) <= 3 ) {
                // Replace user_login with user_email
                $columns = array_map( function( $col ) {
                    return 'user_login' === $col ? 'user_email' : $col;
                }, $columns );
            }
        } else {
            // Use default columns - show display_name and email when no custom columns
            $columns = [ 'avatar', 'display_name', 'user_email' ];
        }

        // Check if avatar should be shown in table layout (layout-1)
        $directory_layout = ! empty( $attributes['directory_layout'] ) ? $attributes['directory_layout'] : 'layout-1';

        // Handle show_avatar_in_table - default to true if not set
        $show_avatar_in_table = true;
        if ( isset( $attributes['show_avatar_in_table'] ) ) {
            // Handle various possible values (boolean, string, numeric)
            $show_avatar_in_table = filter_var( $attributes['show_avatar_in_table'], FILTER_VALIDATE_BOOLEAN );
        }

        // Handle avatar column based on layout and settings
        if ( 'layout-1' === $directory_layout ) {
            $has_avatar = in_array( 'avatar', $columns );

            if ( $show_avatar_in_table && ! $has_avatar ) {
                // Add avatar to the beginning if it should be shown but isn't in columns
                array_unshift( $columns, 'avatar' );
            } elseif ( ! $show_avatar_in_table && $has_avatar ) {
                // Remove avatar if it shouldn't be shown but is in columns
                $columns = array_values( array_diff( $columns, [ 'avatar' ] ) );
            }
        }

        // Get dynamic meta field columns - check both new and legacy
        $meta_field_columns = [];
        if ( ! empty( $attributes['id'] ) ) {
            $meta_field_columns = $this->get_meta_field_columns( $attributes['id'] );
        } elseif ( ! empty( $attributes['legacy_meta_fields'] ) ) {
            // Use legacy meta fields if passed from convert_legacy_settings_to_atts
            $meta_field_columns = $attributes['legacy_meta_fields'];
        } else {
            // Try to get from legacy settings even without ID
            $meta_field_columns = $this->get_legacy_meta_field_columns();
        }

        // Add meta field columns to the columns array
        if ( ! empty( $meta_field_columns ) ) {
            foreach ( $meta_field_columns as $meta_key => $label ) {
                // Only add if not already in columns
                if ( ! in_array( $meta_key, $columns ) ) {
                    $columns[] = $meta_key;
                }
            }
        }

        // Prepare all_data array (used by templates)
        $all_data = array_merge( $attributes, [
            'id'                => $attributes['id'], // Add directory ID for data-directory-id attribute
            'max_item'          => $attributes['max_item'] ?? null, // Add max_item for total users limit
            'max_item_per_page' => $attributes['per_page'],
            'columns'           => $columns,
            'meta_field_columns' => $meta_field_columns, // Add meta field columns for template headers
            'enable_search'     => $attributes['enable_search'] === 'yes',
            'enable_frontend_sorting' => $attributes['enable_frontend_sorting'] === 'yes',
            'profile_permalink' => $attributes['profile_permalink'],
            'profile_layout'    => $attributes['profile_layout'], // Add profile layout for profile view
            'directory_layout'  => $attributes['directory_layout'], // Add this for AJAX search/pagination
            'orderby'           => $attributes['orderby'],
            'order'             => $attributes['order'],
            'social_fields'     => $attributes['social_fields'], // Add social fields for filtering
            'is_shortcode'      => true, // Flag to indicate this is a shortcode-based directory
            'exclude_users'     => $attributes['exclude_users'], // Add exclude users for filtering
            'show_avatar_in_table' => $show_avatar_in_table, // Add show_avatar_in_table for AJAX
        ] );

        return [
            'all_data'      => $all_data,
            'columns'       => $columns,
            'users'         => $users,
            'total'         => $total,
            'avatar_size'   => $attributes['avatar_size'],
            'enable_search' => $attributes['enable_search'] === 'yes',
            'enable_frontend_sorting' => $attributes['enable_frontend_sorting'] === 'yes',
            'page_id'       => get_the_ID(),
            'block_id'      => $instance_id,
            'directory_layout' => $attributes['directory_layout'], // Add layout info for templates
            'social_fields' => $attributes['social_fields'], // Add social fields for filtering
            'pagination'    => [
                'total_pages'  => $total_pages,
                'total_items'  => $total,
                'per_page'     => $attributes['per_page'],
                'current_page' => $current_page,
            ],
            'profile_url_helper' => [ $this, 'get_profile_url' ],
        ];
    }

    /**
     * Parse roles attribute
     *
     * @since 4.2.0
     *
     * @param string $role_string Comma-separated roles
     *
     * @return array
     */
    private function parse_roles( $role_string ) {
        if ( empty( $role_string ) || 'all' === $role_string ) {
            return [ 'all' ];
        }

        $roles = array_map( 'trim', explode( ',', $role_string ) );
        return array_filter( $roles );
    }

    /**
     * Get current page number
     *
     * @since 4.2.0
     *
     * @return int
     */
    private function get_current_page() {
        $current_page = 1;

        // Support both ?page=2 and /page/2/
        if ( get_query_var( 'paged' ) ) {
            $current_page = (int) get_query_var( 'paged' );
        } elseif ( ! empty( $_GET['page'] ) ) {
            $current_page = (int) $_GET['page'];
        }

        return max( 1, $current_page );
    }

    /**
     * Get layout template name
     *
     * @since 4.2.0
     *
     * @param string $layout Layout identifier
     *
     * @return string
     */
    private function get_layout_template( $layout ) {
        // Validate layout exists
        $available_layouts = [ 'layout-1', 'layout-2', 'layout-3', 'layout-4', 'layout-5', 'layout-6', 'layout-7', 'layout-8', 'layout-9', 'layout-10' ];

        if ( in_array( $layout, $available_layouts, true ) ) {
            return $layout;
        }

        return 'layout-1'; // Default fallback
    }

    /**
     * Generate profile URL based on permalink setting
     *
     * @since 4.2.0
     *
     * @param WP_User $user User object
     * @param string $permalink_type Type of permalink ('username' or 'user_id')
     *
     * @return string Profile URL
     */
    public function get_profile_url( $user, $permalink_type = 'username' ) {
        $current_url = get_permalink();

        // Remove trailing slash for clean URL
        $current_url = rtrim( $current_url, '/' );

        if ( 'user_id' === $permalink_type ) {
            // Clean URL format: /ud/123
            return $current_url . '/' . $user->ID;
        }

        // Default to username - Clean URL format: /ud/username
        return $current_url . '/' . $user->user_login;
    }

    /**
     * Convert layout name to row variant name
     *
     * @since 4.2.0
     *
     * @param string $layout Layout identifier (e.g., 'layout-2')
     *
     * @return string Row variant identifier (e.g., 'row-2')
     */
    private function layout_to_row_variant( $layout ) {
        // Convert 'layout-X' to 'row-X'
        return str_replace( 'layout-', 'row-', $layout );
    }

    /**
     * Check if we should show profile instead of listing
     *
     * @since 4.2.0
     *
     * @param string $profile_permalink Profile permalink setting
     *
     * @return bool
     */
    private function should_show_profile( $profile_permalink ) {
        // Check for profile query parameters based on profile_permalink setting
        if ( 'username' === $profile_permalink || 'user_login' === $profile_permalink ) {
            return ! empty( $_GET['user'] );
        }

        // Check for user_id parameter
        if ( 'user_id' === $profile_permalink ) {
            return ! empty( $_GET['user_id'] );
        }

        // Default fallback
        return ! empty( $_GET['user'] ) || ! empty( $_GET['user_id'] );
    }

    /**
     * Check if current request is for profile view
     *
     * @since 4.2.0
     *
     * @return bool
     */
    private function is_profile_view() {
        // Check for pretty URL query var (set by rewrite rules)
        if ( get_query_var( 'wpuf_user_profile' ) ) {
            return true;
        }

        // Backward compatibility: Check for query parameters
        if ( ! empty( $_GET['username'] ) || ! empty( $_GET['user_id'] ) ||
             ! empty( $_GET['user'] ) || ! empty( $_GET['id'] ) ) {
            return true;
        }

        return false;
    }

    /**
     * Get profile user from URL parameters
     *
     * @since 4.2.0
     *
     * @param array $attributes Shortcode attributes
     *
     * @return WP_User|false User object if profile view is detected, false otherwise
     */
    private function get_profile_user( $attributes ) {
        if ( ! $this->is_profile_view() ) {
            return false;
        }

        $profile_base = $attributes['profile_permalink'];
        $user_identifier = null;

        // First try to get from pretty URL query var (set by rewrite rules)
        $user_identifier = get_query_var( 'wpuf_user_profile' );

        // If we have a user identifier from pretty URL
        if ( ! empty( $user_identifier ) ) {
            // Decode URL-encoded characters (like %20 for spaces)
            $user_identifier = urldecode( $user_identifier );
            // Sanitize the identifier
            $user_identifier = sanitize_text_field( $user_identifier );

            // Try to determine if it's a user ID or username based on wizard setting
            if ( 'user_id' === $profile_base && is_numeric( $user_identifier ) ) {
                // If expecting user_id and it's numeric
                $user_id = absint( $user_identifier );
                if ( $user_id > 0 ) {
                    $user = get_user_by( 'ID', $user_id );
                    if ( $user ) return $user;
                }
            } else {
                // Try username lookup first
                $user = get_user_by( 'login', $user_identifier );
                if ( $user ) {
                    return $user;
                }

                // If profile_base is user_id but identifier is not numeric,
                // or if username lookup failed, try ID lookup as last resort
                if ( is_numeric( $user_identifier ) ) {
                    $user_id = absint( $user_identifier );
                    if ( $user_id > 0 ) {
                        $user = get_user_by( 'ID', $user_id );
                        if ( $user ) return $user;
                    }
                }
            }
        }

        // Additional fallback logic - try all parameters regardless of profile_base setting
        // This ensures backward compatibility and handles mixed scenarios

        // Try username-based parameters
        if ( ! empty( $_GET['username'] ) ) {
            $user_identifier = sanitize_text_field( wp_unslash( $_GET['username'] ) );
            $user = get_user_by( 'login', $user_identifier );
            if ( $user ) return $user;
        }

        if ( ! empty( $_GET['user'] ) ) {
            $user_identifier = sanitize_text_field( wp_unslash( $_GET['user'] ) );
            $user = get_user_by( 'login', $user_identifier );
            if ( $user ) return $user;
        }

        // Try ID-based parameters
        if ( ! empty( $_GET['user_id'] ) ) {
            $user_id = absint( $_GET['user_id'] );
            if ( $user_id > 0 ) {
                $user = get_user_by( 'ID', $user_id );
                if ( $user ) return $user;
            }
        }

        if ( ! empty( $_GET['id'] ) ) {
            $user_id = absint( $_GET['id'] );
            if ( $user_id > 0 ) {
                $user = get_user_by( 'ID', $user_id );
                if ( $user ) return $user;
            }
        }

        return false;
    }

    /**
     * Render profile view
     *
     * @since 4.2.0
     *
     * @param WP_User $user User object
     * @param array $attributes Shortcode attributes
     *
     * @return string
     */
    private function render_profile_view( $user, $attributes ) {
        if ( ! $user || is_wp_error( $user ) ) {
            return '<div class="wpuf-error">' . __( 'User not found.', 'wpuf-pro' ) . '</div>';
        }

        // Prepare data for profile template
        $tabs = explode( ',', $attributes['default_tabs'] );

        // Only add activity tab automatically if:
        // 1. User Activity module is active
        // 2. Activity tab is not already in the tabs list
        // 3. We're dealing with legacy shortcodes (no stored settings) OR activity is explicitly enabled in settings
        $should_add_activity = false;
        if ( class_exists( 'WPUF_User_Activity' ) && ! in_array( 'activity', $tabs ) ) {
            if ( ! empty( $attributes['id'] ) ) {
                // For stored settings, check if activity is in the enabled tabs
                $directory_post = get_post( $attributes['id'] );
                if ( $directory_post && $directory_post->post_type === 'wpuf_user_listing' ) {
                    $stored_settings = json_decode( $directory_post->post_content, true ) ?: [];
                    $profile_tabs = $stored_settings['profile_tabs'] ?? [];
                    $should_add_activity = in_array( 'activity', $profile_tabs );
                }
            } else {
                // For legacy shortcodes without ID, add activity by default (backward compatibility)
                $should_add_activity = true;
            }
        }

        if ( $should_add_activity ) {
            $tabs[] = 'activity';
        }

        // Get custom tab labels if available
        $custom_tab_labels = [];
        if ( ! empty( $attributes['id'] ) ) {
            $directory_post = get_post( $attributes['id'] );
            if ( $directory_post && $directory_post->post_type === 'wpuf_user_listing' ) {
                $stored_settings = json_decode( $directory_post->post_content, true ) ?: [];
                $custom_tab_labels = $stored_settings['profile_tabs_labels'] ?? [];
            }
        } else {
            // Check legacy settings for tab labels
            $legacy_settings = get_option( 'wpuf_userlisting', [] );
            if ( ! empty( $legacy_settings['profile_tabs'] ) ) {
                foreach ( $legacy_settings['profile_tabs'] as $tab_id => $tab ) {
                    if ( ! empty( $tab['label'] ) ) {
                        $custom_tab_labels[$tab_id] = $tab['label'];
                    }
                }
            }
        }

        $all_data = [
            'user'              => $user,
            'profile_base'      => $attributes['profile_permalink'] === 'username' ? 'user_login' : 'user_id',
            'profile_layout'    => $attributes['profile_layout'],
            'show_avatar'       => true,
            'enable_tabs'       => true,
            'default_tabs'      => $tabs,
            'default_active_tab'=> 'about',
            'avatar_size'       => $attributes['avatar_size'],
            'show_bio'          => true,
            'profile_fields'    => [ 'username', 'display_name', 'email', 'website' ],
            'custom_fields'     => [],
            'posts_per_tab'     => 5,
            'gallery_img_size'  => $attributes['gallery_img_size'],
            'social_fields'     => $attributes['social_fields'],
            'custom_tab_labels' => $custom_tab_labels,
            'directory_id'      => $attributes['id'], // Pass directory ID for dynamic fields
            'id'                => $attributes['id'], // Alternative key
        ];

        // Add CSS to hide page title on profile pages (works for both block and classic themes)
        add_action( 'wp_head', function() {
            if ( is_main_query() && ! is_admin() ) {
                echo '<style>
                    /* Block themes */
                    .wp-block-post-title { display: none !important; }

                    /* Classic themes - common selectors */
                    .entry-title { display: none !important; }
                    .page-title { display: none !important; }
                    .post-title { display: none !important; }
                    h1.entry-title { display: none !important; }
                    .single .entry-header .entry-title { display: none !important; }
                    .page-header .page-title { display: none !important; }

                    /* Popular theme specific selectors */
                    .content-title { display: none !important; }
                    .main-title { display: none !important; }
                    .article-title { display: none !important; }
                </style>';
            }
        }, 10 );

        // Fix document title separator to use pipe instead of dash
        add_filter( 'document_title_separator', function( $sep ) {
            return '|';
        }, 10, 1 );

        // Enqueue avatar and cover photo upload assets for profile view
        $this->enqueue_avatar_upload_assets();
        $this->enqueue_cover_photo_upload_assets();

        // Enqueue unified profile layout script with layout-specific config
        $layout_configs = [
            'layout-1' => [
                'tabButtonClass'    => '.wpuf-tab-button',
                'containerClass'    => '.wpuf-profile-layout-1',
                'tabContentClass'   => '',
                'tabContentSelector' => '[class^="wpuf-tab-content-"]',
                'activeClass'       => '!wpuf-text-gray-900',
                'inactiveClass'     => '!wpuf-text-gray-500',
            ],
            'layout-2' => [
                'tabButtonClass'    => '.wpuf-tab-button-2',
                'containerClass'    => '.wpuf-profile-layout-2',
                'tabContentClass'   => '.wpuf-tab-content-2',
                'tabContentSelector' => '',
                'activeClass'       => '',
                'inactiveClass'     => '',
            ],
            'layout-3' => [
                'tabButtonClass'    => '.wpuf-tab-button-3',
                'containerClass'    => '.wpuf-profile-layout-3',
                'tabContentClass'   => '.wpuf-tab-content-3',
                'tabContentSelector' => '',
                'activeClass'       => '',
                'inactiveClass'     => '',
            ],
            'layout-4' => [
                'tabButtonClass'    => '.wpuf-tab-button',
                'containerClass'    => '.wpuf-profile-layout-4',
                'tabContentClass'   => '',
                'tabContentSelector' => '[class^="wpuf-tab-content-"]',
                'activeClass'       => '!wpuf-text-purple-600',
                'inactiveClass'     => '!wpuf-text-gray-500',
            ],
        ];

        $current_layout = $attributes['profile_layout'];

        if ( isset( $layout_configs[ $current_layout ] ) ) {
            wp_enqueue_script(
                'wpuf-ud-profile-layout',
                WPUF_UD_ROOT_URI . '/src/js/profile-layout.js',
                [ 'jquery' ],
                WPUF_UD_VERSION,
                true
            );

            wp_localize_script(
                'wpuf-ud-profile-layout',
                'wpuf_ud_profile_config',
                $layout_configs[ $current_layout ]
            );
        }

        // Start output buffering
        ob_start();

        // Load the profile template
        wpuf_load_pro_template( 'user-profile.php', [
            'template_data' => $all_data,
            'profile_layout' => $attributes['profile_layout']
        ], WPUF_UD_TEMPLATES . '/shortcodes/profile/' );

        return ob_get_clean();
    }

    /**
     * Get profile fields from stored directory settings
     *
     * @since 4.2.0
     *
     * @param string $directory_id Directory post ID
     *
     * @return array Profile fields configuration
     */
    public static function get_profile_fields( $directory_id ) {
        // If no directory ID, check for legacy settings
        if ( empty( $directory_id ) ) {
            return self::get_legacy_profile_fields();
        }

        // Get directory settings from database
        $directory_post = get_post( $directory_id );
        if ( ! $directory_post || 'wpuf_user_listing' !== $directory_post->post_type ) {
            // Fallback to legacy if new directory not found
            return self::get_legacy_profile_fields();
        }

        // Parse stored settings
        $stored_settings = [];
        if ( ! empty( $directory_post->post_content ) ) {
            $stored_settings = json_decode( $directory_post->post_content, true ) ?: [];
        }


        // Get about tab fields - they are stored under 'about_tabs_content'
        $about_fields = $stored_settings['about_tabs_content'] ?? [];

        return $about_fields;
    }

    /**
     * Get legacy profile fields from wpuf_userlisting option
     *
     * @since 4.2.0
     *
     * @return array Profile fields configuration in new format
     */
    private static function get_legacy_profile_fields() {
        $legacy_settings = get_option( 'wpuf_userlisting', [] );

        if ( empty( $legacy_settings['fields'] ) ) {
            return [];
        }

        $converted_fields = [];

        foreach ( $legacy_settings['fields'] as $field ) {
            // Only process meta fields for about section
            if ( $field['type'] !== 'meta' ) {
                continue;
            }

            // Convert to new format
            $converted_field = [
                'type' => 'meta_field',
                'meta_key' => $field['meta'],
                'label' => $field['label'] ?? $field['meta'],
                'show_in_listing' => isset( $field['in_table'] ) && $field['in_table'] === 'yes',
                'profile_user_role' => isset( $field['all_user_role'] ) ? $field['all_user_role'] : 'all',
                'viewer_role' => isset( $field['current_user_role'] ) ? $field['current_user_role'] : 'all',
            ];

            $converted_fields[] = $converted_field;
        }

        return $converted_fields;
    }

    /**
     * Get meta field columns marked for table display
     *
     * @since 4.2.0
     *
     * @param string $directory_id Directory post ID
     *
     * @return array Array of meta_key => label pairs
     */
    private function get_meta_field_columns( $directory_id ) {
        // If no directory ID, check legacy settings
        if ( empty( $directory_id ) ) {
            return $this->get_legacy_meta_field_columns();
        }

        // Get directory settings from database
        $directory_post = get_post( $directory_id );
        if ( ! $directory_post || 'wpuf_user_listing' !== $directory_post->post_type ) {
            // Fallback to legacy if new directory not found
            return $this->get_legacy_meta_field_columns();
        }

        // Parse stored settings
        $stored_settings = [];
        if ( ! empty( $directory_post->post_content ) ) {
            $stored_settings = json_decode( $directory_post->post_content, true ) ?: [];
        }

        // Get about tab fields that are marked for table display
        $about_fields = $stored_settings['about_tabs_content'] ?? [];
        $meta_columns = [];

        foreach ( $about_fields as $field ) {
            // Check if this is a meta field and is marked to show in listing
            if ( 'meta_field' === $field['type'] && ! empty( $field['show_in_listing'] ) && ! empty( $field['meta_key'] ) ) {
                // Use label if provided, otherwise use meta_key
                $label = ! empty( $field['label'] ) ? $field['label'] : $field['meta_key'];
                $meta_columns[ $field['meta_key'] ] = $label;
            }
        }

        return $meta_columns;
    }

    /**
     * Get legacy meta field columns from wpuf_userlisting option
     *
     * @since 4.2.0
     *
     * @return array Array of meta_key => label pairs
     */
    private function get_legacy_meta_field_columns() {
        $legacy_settings = get_option( 'wpuf_userlisting', [] );

        if ( empty( $legacy_settings['fields'] ) ) {
            return [];
        }

        $meta_columns = [];

        foreach ( $legacy_settings['fields'] as $field ) {
            // Check if this is a meta field marked for table display
            if ( $field['type'] === 'meta' && isset( $field['in_table'] ) && $field['in_table'] === 'yes' && ! empty( $field['meta'] ) ) {
                $label = ! empty( $field['label'] ) ? $field['label'] : $field['meta'];
                $meta_columns[ $field['meta'] ] = $label;
            }
        }

        return $meta_columns;
    }

    /**
     * Get valid orderby fields (core fields + meta fields with show_in_listing enabled)
     *
     * @since 4.2.0
     *
     * @param string|null $directory_id Directory post ID
     * @return array Array of valid orderby field names
     */
    private function get_valid_orderby_fields( $directory_id = null ) {
        // Core user fields that are always valid - include both formats for compatibility
        $core_fields = [
            'id', 'ID',
            'username', 'user_login',
            'email', 'user_email',
            'display_name',
            'user_registered', 'registered'
        ];

        // If no directory ID, return only core fields
        if ( empty( $directory_id ) ) {
            return $core_fields;
        }

        // Get meta fields that are marked for search/listing
        $enabled_meta_fields = $this->get_meta_fields_for_search_and_order( $directory_id );

        // Combine core fields with enabled meta fields
        return array_merge( $core_fields, array_keys( $enabled_meta_fields ) );
    }

    /**
     * Normalize orderby field name for consistency
     *
     * @since 4.2.0
     *
     * @param string $field The field name to normalize
     * @return string Normalized field name
     */
    private function normalize_orderby_field( $field ) {
        // Map wizard-saved field names to standard WordPress field names
        $field_mapping = [
            'username' => 'user_login',
            'email' => 'user_email',
            'registered' => 'user_registered',
        ];

        // Return mapped value if exists, otherwise return original
        return isset( $field_mapping[ $field ] ) ? $field_mapping[ $field ] : $field;
    }

    /**
     * Get meta fields enabled for search and ordering (show_in_listing = true)
     *
     * @since 4.2.0
     *
     * @param string $directory_id Directory post ID
     * @return array Array of meta_key => label pairs
     */
    private function get_meta_fields_for_search_and_order( $directory_id ) {
        // If no directory ID, check legacy settings
        if ( empty( $directory_id ) ) {
            return $this->get_legacy_meta_fields_for_search_and_order();
        }

        // Get directory settings from database
        $directory_post = get_post( $directory_id );
        if ( ! $directory_post || 'wpuf_user_listing' !== $directory_post->post_type ) {
            // Fallback to legacy if new directory not found
            return $this->get_legacy_meta_fields_for_search_and_order();
        }

        // Parse stored settings
        $stored_settings = [];
        if ( ! empty( $directory_post->post_content ) ) {
            $stored_settings = json_decode( $directory_post->post_content, true ) ?: [];
        }

        // Get about tab fields that are marked for search/listing
        $about_fields = $stored_settings['about_tabs_content'] ?? [];
        $enabled_meta_fields = [];

        foreach ( $about_fields as $field ) {
            // Check if this is a meta field and is marked for search by meta checkbox
            if ( 'meta_field' === $field['type'] && ! empty( $field['search_by_meta'] ) && ! empty( $field['meta_key'] ) ) {
                // Use label if provided, otherwise use meta_key
                $label = ! empty( $field['label'] ) ? $field['label'] : $field['meta_key'];
                $enabled_meta_fields[ $field['meta_key'] ] = $label;
            }
        }

        return $enabled_meta_fields;
    }

    /**
     * Get legacy meta fields for search and ordering from wpuf_userlisting option
     *
     * @since 4.2.0
     *
     * @return array Array of meta_key => label pairs
     */
    private function get_legacy_meta_fields_for_search_and_order() {
        $legacy_settings = get_option( 'wpuf_userlisting', [] );

        if ( empty( $legacy_settings['fields'] ) ) {
            return [];
        }

        $enabled_meta_fields = [];

        foreach ( $legacy_settings['fields'] as $field ) {
            // Check search_by or sort_by flags for legacy fields
            if ( $field['type'] === 'meta' && ! empty( $field['meta'] ) ) {
                $is_searchable = isset( $field['search_by'] ) && $field['search_by'] === 'yes';
                $is_sortable = isset( $field['sort_by'] ) && $field['sort_by'] === 'yes';
                $is_in_table = isset( $field['in_table'] ) && $field['in_table'] === 'yes';

                // Include if any of these flags are set
                if ( $is_searchable || $is_sortable || $is_in_table ) {
                    $label = ! empty( $field['label'] ) ? $field['label'] : $field['meta'];
                    $enabled_meta_fields[ $field['meta'] ] = $label;
                }
            }
        }

        return $enabled_meta_fields;
    }

    /**
     * Get valid search fields - synced with Blocks::get_searchable_fields()
     *
     * @since 4.2.0
     *
     * @return array Array of valid search field names
     */
    private function get_valid_search_fields() {
        // Core user fields - synced with Blocks::get_searchable_fields()
        $core_fields = [ 'user_login', 'user_email', 'display_name' ];

        // Get usermeta keys - synced with Blocks::get_searchable_fields()
        $meta_fields_data = wpuf_get_user_meta_fields();
        $meta_fields = is_array( $meta_fields_data ) ? array_keys( $meta_fields_data ) : [];

        return array_merge( $core_fields, $meta_fields );
    }

    /**
     * Get searchable and orderable meta fields for frontend display
     *
     * @since 4.2.0
     *
     * @param string|null $directory_id Directory post ID
     * @return array Array of field data for frontend display
     */
    public function get_available_fields_for_directory( $directory_id = null ) {
        $response = [];

        // Define profile field keys (core WordPress user table + common user meta)
        $profile_field_keys = [
            'user_login', 'user_email', 'display_name', 'user_url', 'user_registered',
            'first_name', 'last_name', 'nickname', 'description'
        ];

        // Core/Profile fields - searchable
        $response['core_fields'] = [
            'search_fields' => [
                ['value' => 'user_login', 'label' => __( 'Username', 'wpuf-pro' )],
                ['value' => 'user_email', 'label' => __( 'Email', 'wpuf-pro' )],
                ['value' => 'display_name', 'label' => __( 'Display Name', 'wpuf-pro' )],
                ['value' => 'user_url', 'label' => __( 'Website', 'wpuf-pro' )],
                ['value' => 'first_name', 'label' => __( 'First Name', 'wpuf-pro' )],
                ['value' => 'last_name', 'label' => __( 'Last Name', 'wpuf-pro' )],
                ['value' => 'nickname', 'label' => __( 'Nickname', 'wpuf-pro' )],
                ['value' => 'description', 'label' => __( 'Biographical Info', 'wpuf-pro' )],
            ],
            'order_fields' => [
                ['value' => 'id', 'label' => __( 'User ID', 'wpuf-pro' )],
                ['value' => 'user_login', 'label' => __( 'Username', 'wpuf-pro' )],
                ['value' => 'user_email', 'label' => __( 'Email', 'wpuf-pro' )],
                ['value' => 'display_name', 'label' => __( 'Display Name', 'wpuf-pro' )],
                ['value' => 'user_url', 'label' => __( 'Website', 'wpuf-pro' )],
                ['value' => 'user_registered', 'label' => __( 'Registration Date', 'wpuf-pro' )],
                ['value' => 'first_name', 'label' => __( 'First Name', 'wpuf-pro' )],
                ['value' => 'last_name', 'label' => __( 'Last Name', 'wpuf-pro' )],
                ['value' => 'nickname', 'label' => __( 'Nickname', 'wpuf-pro' )],
                ['value' => 'description', 'label' => __( 'Biographical Info', 'wpuf-pro' )],
            ]
        ];

        // Custom meta fields (only if directory ID provided, excluding profile fields)
        // NOTE: "Search by this meta in user listing table" checkbox only affects search dropdown
        // Sort dropdown shows all meta fields regardless of checkbox
        $response['meta_fields'] = [];
        $response['searchable_meta_fields'] = [];

        if ( ! empty( $directory_id ) ) {
            // Get meta fields marked for search (show_in_listing checkbox checked)
            $searchable_meta_fields = $this->get_meta_fields_for_search_and_order( $directory_id );

            // Get ALL meta fields for ordering (checkbox doesn't affect sort dropdown)
            $all_meta_fields = $this->get_all_meta_fields_for_directory( $directory_id );

            // Filter out profile fields from searchable meta fields
            foreach ( $searchable_meta_fields as $meta_key => $label ) {
                if ( ! in_array( $meta_key, $profile_field_keys, true ) ) {
                    $response['searchable_meta_fields'][] = ['value' => $meta_key, 'label' => $label];
                }
            }

            // Filter out profile fields from all meta fields (for ordering)
            foreach ( $all_meta_fields as $meta_key => $label ) {
                if ( ! in_array( $meta_key, $profile_field_keys, true ) ) {
                    $response['meta_fields'][] = ['value' => $meta_key, 'label' => $label];
                }
            }
        }

        return $response;
    }

    /**
     * Get ALL meta fields for a directory (for ordering dropdown - no filtering)
     *
     * @since 4.2.3
     *
     * @param string $directory_id Directory post ID
     * @return array Array of meta_key => label pairs
     */
    private function get_all_meta_fields_for_directory( $directory_id ) {
        // Get directory settings from database
        $directory_post = get_post( $directory_id );
        if ( ! $directory_post || 'wpuf_user_listing' !== $directory_post->post_type ) {
            return [];
        }

        // Parse stored settings
        $stored_settings = [];
        if ( ! empty( $directory_post->post_content ) ) {
            $stored_settings = json_decode( $directory_post->post_content, true ) ?: [];
        }

        // Get about tab fields - ALL meta fields regardless of show_in_listing checkbox
        $about_fields = $stored_settings['about_tabs_content'] ?? [];
        $all_meta_fields = [];

        foreach ( $about_fields as $field ) {
            // Get ALL meta fields (no show_in_listing filter for ordering)
            if ( 'meta_field' === $field['type'] && ! empty( $field['meta_key'] ) ) {
                // Use label if provided, otherwise use meta_key
                $label = ! empty( $field['label'] ) ? $field['label'] : $field['meta_key'];
                $all_meta_fields[ $field['meta_key'] ] = $label;
            }
        }

        return $all_meta_fields;
    }

    /**
     * Check if current user can see a field based on roles
     *
     * @since 4.2.0
     *
     * @param string $profile_role Profile user's role
     * @param array $field Field configuration
     * @param string $viewer_role Current viewer's role
     *
     * @return bool
     */
    public static function can_user_see_field( $profile_role, $field, $viewer_role ) {
        // Check profile user role permissions
        if ( ! empty( $field['profile_user_role'] ) && $field['profile_user_role'] !== 'all' ) {
            $allowed_roles = is_array( $field['profile_user_role'] ) ? $field['profile_user_role'] : [ $field['profile_user_role'] ];

            // If 'all' is not in the allowed roles and the profile role is not in the allowed roles, deny access
            if ( ! in_array( 'all', $allowed_roles, true ) && ! in_array( $profile_role, $allowed_roles, true ) ) {
                return false;
            }
        }

        // Check viewer role permissions
        if ( ! empty( $field['viewer_role'] ) && $field['viewer_role'] !== 'all' ) {
            $allowed_viewer_roles = is_array( $field['viewer_role'] ) ? $field['viewer_role'] : [ $field['viewer_role'] ];

            // If 'all' is in the allowed viewer roles, grant access to everyone
            if ( in_array( 'all', $allowed_viewer_roles, true ) ) {
                return true;
            }

            // Handle special 'guest' option - means everyone including logged-in users
            if ( in_array( 'guest', $allowed_viewer_roles, true ) ) {
                return true;
            }

            // Handle special 'logged_in' option - means any authenticated user
            if ( in_array( 'logged_in', $allowed_viewer_roles, true ) ) {
                // If viewer_role is 'guest', they are not logged in, so deny access
                if ( $viewer_role === 'guest' ) {
                    return false;
                }
                // Any other role means they are logged in
                return true;
            }

            // Standard role check: viewer role must be in the allowed viewer roles
            if ( ! in_array( $viewer_role, $allowed_viewer_roles, true ) ) {
                return false;
            }
        }

        return true;
    }

    /**
     * Extract user IDs from excluded_users array
     * Handles both formats: array of objects [{id: 1, name: "admin"}] or array of IDs [1, 2, 3]
     *
     * @since 4.2.0
     *
     * @param array $excluded_users Array of user objects or user IDs
     *
     * @return array Array of user IDs
     */
    private function extract_user_ids_from_excluded_users( $excluded_users ) {
        if ( ! is_array( $excluded_users ) || empty( $excluded_users ) ) {
            return [];
        }

        $user_ids = [];

        foreach ( $excluded_users as $user ) {
            if ( is_array( $user ) && isset( $user['id'] ) ) {
                // User object format: {id: 1, name: "admin"}
                $user_ids[] = intval( $user['id'] );
            } elseif ( is_object( $user ) && isset( $user->id ) ) {
                // User object format: object with id property
                $user_ids[] = intval( $user->id );
            } elseif ( is_numeric( $user ) ) {
                // Already a user ID
                $user_ids[] = intval( $user );
            }
        }

        return array_filter( array_unique( $user_ids ) ); // Remove duplicates and zeros
    }

    /**
     * Modify page title for user profile pages (WordPress 5.0+)
     *
     * @since 4.2.0
     *
     * @param array $title_parts The document title parts
     * @return array Modified title parts
     */
    public function modify_profile_page_title( $title_parts ) {
        // Check if we're on a profile view
        if ( ! $this->is_profile_view() ) {
            return $title_parts;
        }

        // Get the profile user
        $attributes = [ 'profile_permalink' => 'username' ]; // Default
        $profile_user = $this->get_profile_user( $attributes );

        if ( $profile_user && ! is_wp_error( $profile_user ) ) {
            // Set title to "First Name Last Name | Site Name"
            $first_name = get_user_meta( $profile_user->ID, 'first_name', true );
            $last_name = get_user_meta( $profile_user->ID, 'last_name', true );

            // Build the full name, fallback to display_name if names not set
            if ( $first_name || $last_name ) {
                $full_name = trim( $first_name . ' ' . $last_name );
            } else {
                $full_name = $profile_user->display_name;
            }

            $title_parts['title'] = $full_name;
        }

        return $title_parts;
    }

    /**
     * Modify page title for user profile pages (Legacy support for older WP versions)
     *
     * @since 4.2.0
     *
     * @param string $title The page title
     * @param string $sep The separator
     * @return string Modified title
     */
    public function modify_profile_page_title_legacy( $title, $sep = '|' ) {
        // Check if we're on a profile view
        if ( ! $this->is_profile_view() ) {
            return $title;
        }

        // Get the profile user
        $attributes = [ 'profile_permalink' => 'username' ]; // Default
        $profile_user = $this->get_profile_user( $attributes );

        if ( $profile_user && ! is_wp_error( $profile_user ) ) {
            // Set title to "First Name Last Name | Site Name"
            $first_name = get_user_meta( $profile_user->ID, 'first_name', true );
            $last_name = get_user_meta( $profile_user->ID, 'last_name', true );

            // Build the full name, fallback to display_name if names not set
            if ( $first_name || $last_name ) {
                $full_name = trim( $first_name . ' ' . $last_name );
            } else {
                $full_name = $profile_user->display_name;
            }

            $site_name = get_bloginfo( 'name' );
            return $full_name . ' ' . $sep . ' ' . $site_name;
        }

        return $title;
    }

    /**
     * Enqueue avatar upload assets
     *
     * @since 4.2.7
     *
     * @return void
     */
    private function enqueue_avatar_upload_assets() {
        // Enqueue Cropper.js library (CSS and JS)
        wp_enqueue_style( 'wpuf-ud-cropperjs' );
        wp_enqueue_script( 'wpuf-ud-cropperjs' );

        // Enqueue avatar upload styles
        wp_enqueue_style( 'wpuf-ud-avatar-upload' );

        // Enqueue avatar upload script
        wp_enqueue_script( 'wpuf-ud-avatar-upload' );

        // Localize script with required data
        wp_localize_script(
            'wpuf-ud-avatar-upload',
            'wpuf_ud',
            [
                'ajaxUrl' => admin_url( 'admin-ajax.php' ),
                'nonce'   => wp_create_nonce( 'wpuf_avatar_upload_nonce' ),
            ]
        );
    }

    /**
     * Enqueue cover photo upload assets
     *
     * @since 4.2.7
     *
     * @return void
     */
    private function enqueue_cover_photo_upload_assets() {
        // Enqueue Cropper.js library (CSS and JS)
        wp_enqueue_style( 'wpuf-ud-cropperjs' );
        wp_enqueue_script( 'wpuf-ud-cropperjs' );

        // Enqueue avatar upload styles (contains cover photo styles)
        wp_enqueue_style( 'wpuf-ud-avatar-upload' );

        // Enqueue profile image upload base script
        wp_enqueue_script( 'wpuf-ud-profile-image-upload' );

        // Enqueue cover photo upload script
        wp_enqueue_script( 'wpuf-ud-cover-photo-upload' );

        // Localize script with required data
        wp_localize_script(
            'wpuf-ud-cover-photo-upload',
            'wpuf_ud_cover_photo',
            [
                'ajaxUrl' => admin_url( 'admin-ajax.php' ),
                'nonce'   => wp_create_nonce( 'wpuf_cover_photo_upload_nonce' ),
            ]
        );
    }
}
