/**
 * External dependencies
 */
import clsx from 'clsx';

/**
 * WordPress dependencies
 */
import { memo, useMemo, useState, useEffect, useCallback, useRef } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { __, _x } from '@wordpress/i18n';
import {
	BlockControls,
	BlockContextProvider,
	__experimentalUseBlockPreview as useBlockPreview,
	useBlockProps,
	useInnerBlocksProps,
	store as blockEditorStore,
} from '@wordpress/block-editor';
import { Spinner, ToolbarGroup, SearchControl } from '@wordpress/components';
import { list, grid } from '@wordpress/icons';
import apiFetch from '@wordpress/api-fetch';



function UserTemplateInnerBlocks({ classList }) {
	const innerBlocksProps = useInnerBlocksProps(
		{ className: clsx('wpuf-user-item class-1', classList) },
		{ __unstableDisableLayoutClassNames: true }
	);
	return <div {...innerBlocksProps} />;
}

function UserTemplateBlockPreview({
	blocks,
	blockContextId,
	classList,
	isHidden,
	setActiveUserContextId,
}) {
	const blockPreviewProps = useBlockPreview({
		blocks,
		props: {
			className: clsx('wpuf-user-item class-2', classList),
		},
	});

	const handleOnClick = () => {
		setActiveUserContextId(blockContextId);
	};

	const style = {
		display: isHidden ? 'none' : undefined,
	};

	return (
		<div
			{...blockPreviewProps}
			tabIndex={0}
			// eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
			role="button"
			onClick={handleOnClick}
			onKeyPress={handleOnClick}
			style={style}
		/>
	);
}

const MemoizedUserTemplateBlockPreview = memo(UserTemplateBlockPreview);



export default function UserTemplateEdit( {
                                              setAttributes,
                                              clientId,
                                              		context: {
			query: {
				perPage,
				offset = 0,
				roles,
				exclude_roles,
				exclude_users,
				order,
				orderBy,
				search,
				exclude,
				include,
				// We gather extra query args to pass to the REST API call.
				// This way extenders of User Directory can add their own query args,
				// and have accurate previews in the editor.
				...restQueryArgs
			} = {},
                                                  templateSlug,
                                                  previewUserType,
                                                  userRoles, // Add this from context
                                                  userExcludeRoles, // Add this from context
                                                  userExcludeUsers, // Add this from context
                                                  usersPerRow, // Add this from context
                                              },
                                              attributes: {layout},
                                              __unstableLayoutClassNames,
                                          } ) {
    const {type: layoutType, columnCount = 3} = layout || {};
    // Use usersPerRow from context if available, otherwise fallback to columnCount or default to 3
    const effectiveColumnCount = usersPerRow || columnCount || 3;
    const [activeUserContextId, setActiveUserContextId] = useState();
    const [users, setUsers] = useState( null );
    const [loading, setLoading] = useState( false );
    const [error, setError] = useState( null );
    
    // Refs for debouncing and tracking previous values
    const debounceTimeoutRef = useRef(null);
    const previousRolesRef = useRef(null);
    const previousExcludeRolesRef = useRef(null);
    const previousExcludeUsersRef = useRef(null);
    const abortControllerRef = useRef(null);

    // Get blocks for template rendering
    const blocks = useSelect(
        ( select ) => select( blockEditorStore ).getBlocks( clientId ),
        [clientId]
    );

	// Fetch users using custom REST endpoint with debouncing
	const fetchUsers = useCallback(async (newRoles = null, newExcludeRoles = null, newExcludeUsers = null) => {

		
		// Cancel previous request if it exists
		if (abortControllerRef.current) {
	
			abortControllerRef.current.abort();
		}
		
		// Create new abort controller
		abortControllerRef.current = new AbortController();
		
		setLoading(true);
		setError(null);

		try {
			// Build query params from context
			const params = new URLSearchParams();

			// Use newRoles if provided, otherwise use context roles
			const rolesToUse = newRoles !== null ? newRoles : (userRoles || roles);
			// Use newExcludeRoles if provided, otherwise use context exclude_roles
			const excludeRolesToUse = newExcludeRoles !== null ? newExcludeRoles : (userExcludeRoles || exclude_roles);
			// Use newExcludeUsers if provided, otherwise use context exclude_users
			const excludeUsersToUse = newExcludeUsers !== null ? newExcludeUsers : (userExcludeUsers || exclude_users);
			

			
			// Check for conflicts between User Roles and Exclude Roles
			if (rolesToUse && rolesToUse !== 'all' && excludeRolesToUse && excludeRolesToUse.length > 0) {
				// Convert both to arrays for comparison
				const selectedRolesArray = Array.isArray(rolesToUse) 
					? rolesToUse 
					: rolesToUse.split(',').map(role => role.trim()).filter(role => role);
				
				const excludeRolesArray = Array.isArray(excludeRolesToUse) 
					? excludeRolesToUse 
					: excludeRolesToUse.split(',').map(role => role.trim()).filter(role => role);
				
				// Find conflicts (roles that appear in both arrays)
				const conflicts = selectedRolesArray.filter(role => excludeRolesArray.includes(role));
				
				if (conflicts.length > 0) {
					setError(__('Conflict detected: The same role(s) cannot be both included and excluded. Please remove the conflicting role(s) from either User Roles or Exclude Roles.', 'wpuf-pro'));
					setLoading(false);
					return;
				}
			}
			
			params.append('per_page', 9); // Limit to 9 users in editor
			params.append('orderby', orderBy || 'id');
			params.append('order', order || 'desc');

			if (rolesToUse && rolesToUse !== 'all') {
				params.append('roles', rolesToUse);
			}

			if (excludeRolesToUse && excludeRolesToUse.length > 0) {
				// Ensure excludeRolesToUse is always an array
				const excludeRolesArray = Array.isArray(excludeRolesToUse) 
					? excludeRolesToUse 
					: excludeRolesToUse.split(',').map(role => role.trim()).filter(role => role);
				
				if (excludeRolesArray.length > 0) {
					params.append('exclude_roles', excludeRolesArray.join(','));
				}
			}

			if (excludeUsersToUse && excludeUsersToUse.length > 0) {
				// Ensure excludeUsersToUse is always an array
				const excludeUsersArray = Array.isArray(excludeUsersToUse) 
					? excludeUsersToUse 
					: excludeUsersToUse.split(',').map(user => user.trim()).filter(user => user);
				
				if (excludeUsersArray.length > 0) {
					params.append('exclude_users', excludeUsersArray.join(','));
				}
			}

			if (search) {
				params.append('search', search);
			}

			if (exclude?.length) {
				params.append('exclude', exclude.join(','));
			}

			if (include?.length) {
				params.append('include', include.join(','));
			}

			const apiUrl = `/wpuf/v1/user_directory/preview?${params.toString()}`;

			// Use custom REST endpoint for preview
			const response = await apiFetch({
				path: apiUrl,
				signal: abortControllerRef.current.signal,
			});

			if (response.success && response.users) {
				setUsers(response.users);
			} else {
				console.error('❌ API call failed - response structure:', response);
				setError(__('Failed to fetch users', 'wpuf-pro'));
			}
		} catch (err) {

			// Don't set error if request was aborted
			if (err.name !== 'AbortError') {
				setError(__('Error fetching users', 'wpuf-pro'));
			}
		} finally {
			setLoading(false);
		}
	}, [userRoles, roles, userExcludeRoles, exclude_roles, userExcludeUsers, exclude_users, orderBy, order, search, exclude, include]);

	// Debounced fetch function
	const debouncedFetchUsers = useCallback((newRoles, newExcludeRoles, newExcludeUsers) => {
		// Clear existing timeout
		if (debounceTimeoutRef.current) {
			clearTimeout(debounceTimeoutRef.current);
		}
		
		// Set new timeout
		debounceTimeoutRef.current = setTimeout(() => {
			fetchUsers(newRoles, newExcludeRoles, newExcludeUsers);
		}, 300);
	}, [fetchUsers]);

	// Watch for filter changes and trigger refetch
	useEffect(() => {
		const currentRoles = userRoles || roles;
		const currentExcludeRoles = userExcludeRoles || exclude_roles;
		const currentExcludeUsers = userExcludeUsers || exclude_users;
		
		// Skip if this is the initial load and we already have users
		if (previousRolesRef.current === null && previousExcludeRolesRef.current === null && previousExcludeUsersRef.current === null && users !== null) {
			previousRolesRef.current = currentRoles;
			previousExcludeRolesRef.current = currentExcludeRoles;
			previousExcludeUsersRef.current = currentExcludeUsers;
			return;
		}
		
		// Check if any filter actually changed
		const rolesChanged = previousRolesRef.current !== currentRoles;
		const excludeRolesChanged = previousExcludeRolesRef.current !== currentExcludeRoles;
		const excludeUsersChanged = previousExcludeUsersRef.current !== currentExcludeUsers;
		
		if (rolesChanged || excludeRolesChanged || excludeUsersChanged) {
			previousRolesRef.current = currentRoles;
			previousExcludeRolesRef.current = currentExcludeRoles;
			previousExcludeUsersRef.current = currentExcludeUsers;
			debouncedFetchUsers(currentRoles, currentExcludeRoles, currentExcludeUsers);
		}
	}, [userRoles, roles, userExcludeRoles, exclude_roles, userExcludeUsers, exclude_users, debouncedFetchUsers, users]);

	// Initial fetch on mount
	useEffect(() => {
		fetchUsers();
	}, []); // Only run on mount

	// Cleanup on unmount
	useEffect(() => {
		return () => {
			if (debounceTimeoutRef.current) {
				clearTimeout(debounceTimeoutRef.current);
			}
			if (abortControllerRef.current) {
				abortControllerRef.current.abort();
			}
		};
	}, []);

	const userContexts = useMemo(
		() =>
			users?.map((user) => ({
				'wpuf-ud/userId': user.id,
				'wpuf-ud/userObject': user,
				'wpuf-ud/isDirectoryMode': true,
				classList: user.class_list ?? '',
			})) || [],
		[users]
	);

	const blockProps = useBlockProps({
		className: clsx(__unstableLayoutClassNames, {
			[`columns-${effectiveColumnCount}`]:
				layoutType === 'grid' && effectiveColumnCount, // Ensure column count is flagged via classname for backwards compatibility.
		}),
	});

	// Block props for the template wrapper to enable style controls
	const templateBlockProps = useBlockProps({
		className: 'wp-block-wpuf-user-directory-item',
	});

	// Show loading spinner that replaces the entire user list
	if (loading) {
		return (
			<div {...blockProps}>
				<div className="wpuf-user-directory-loading" style={{
					display: 'flex',
					justifyContent: 'center',
					alignItems: 'center',
					minHeight: '200px',
					padding: '40px'
				}}>
					<div style={{ textAlign: 'center' }}>
						<Spinner />
						<p style={{ marginTop: '10px', color: '#666' }}>
							{__('Loading users...', 'wpuf-pro')}
						</p>
					</div>
				</div>
			</div>
		);
	}

	// Show error message but keep existing users if available
	if (error) {
		return (
			<div {...blockProps}>
				{users && users.length > 0 ? (
					<>
						<div className="wpuf-user-directory-error" style={{
							background: '#fff3cd',
							border: '1px solid #ffeaa7',
							borderRadius: '4px',
							padding: '10px',
							marginBottom: '20px',
							color: '#856404'
						}}>
							<p style={{ margin: 0 }}>
								{__('Some users may not be displayed due to an error. Showing cached results.', 'wpuf-pro')}
							</p>
						</div>
						{/* Continue with existing user display */}
					</>
				) : (
					<div className="wpuf-user-directory-error" style={{
						display: 'flex',
						justifyContent: 'center',
						alignItems: 'center',
						minHeight: '200px',
						padding: '40px',
						background: '#f8d7da',
						border: '1px solid #f5c6cb',
						borderRadius: '4px',
						color: '#721c24'
					}}>
						<p>{error}</p>
					</div>
				)}
			</div>
		);
	}

	if (!users || !users.length) {
		return (
			<div {...blockProps}>
				<p>{__('No users found.', 'wpuf-pro')}</p>
			</div>
		);
	}

	const setDisplayLayout = (newDisplayLayout) =>
		setAttributes({
			layout: { ...layout, ...newDisplayLayout },
		});

	const displayLayoutControls = [
		{
			icon: list,
			title: _x('List view', 'User template block display setting', 'wpuf-pro'),
			onClick: () => setDisplayLayout({ type: 'default' }),
			isActive: layoutType === 'default' || layoutType === 'constrained',
		},
		{
			icon: grid,
			title: _x('Grid view', 'User template block display setting', 'wpuf-pro'),
			onClick: () =>
				setDisplayLayout({
					type: 'grid',
					columnCount: effectiveColumnCount,
				}),
			isActive: layoutType === 'grid',
		},
	];

	// To avoid flicker when switching active block contexts, a preview is rendered
	// for each block context, but the preview for the active block context is hidden.
	// This ensures that when it is displayed again, the cached rendering of the
	// block preview is used, instead of having to re-render the preview from scratch.
	return (
		<>
			<BlockControls>
				<ToolbarGroup controls={displayLayoutControls} />
			</BlockControls>

            <div className="wpuf-user-list-container">
                <ul className={clsx(
                    'wp-block-post-template',
                    'is-layout-grid',
                    `columns-${effectiveColumnCount}`,
                    'wpuf-ud-list',
                    'wpuf-ud-list-roundGrids',
                    'wpuf-flow-root'
                )} role="list">
                    {userContexts &&
                        userContexts.map((userContext) => (
                            <BlockContextProvider
                                key={userContext['wpuf-ud/userId']}
                                value={userContext}
                            >
                                <li className="wpuf-user-card">
                                    <div {...templateBlockProps}>
                                        							{userContext['wpuf-ud/userId'] ===
                                        (activeUserContextId ||
                                            userContexts[0]?.['wpuf-ud/userId']) ? (
                                            <div className="wp-block-group is-content-justification-center is-layout-flex wp-container-core-group-is-layout-ce155fab wp-block-group-is-layout-flex">
                                                <UserTemplateInnerBlocks
                                                    classList={userContext.classList}
                                                />
                                            </div>
                                        ) : null}
                                        <MemoizedUserTemplateBlockPreview
                                            blocks={blocks}
											blockContextId={userContext['wpuf-ud/userId']}
                                            classList={userContext.classList}
                                            setActiveUserContextId={
                                                setActiveUserContextId
                                            }
                                            isHidden={
                                                							userContext['wpuf-ud/userId'] ===
                                                (activeUserContextId ||
                                                    userContexts[0]?.['wpuf-ud/userId'])
                                            }
                                        />
                                    </div>
                                </li>
                            </BlockContextProvider>
                        ))}
                </ul>
            </div>
		</>
	);
}
