/**
 * External dependencies.
 */
import { useMemo, useState, useEffect } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import {
	Container,
	Input,
	Button,
	Label,
	Title,
	Toaster,
	toast,
} from '@bsf/force-ui';
import {
	Blend,
	Cog,
	LayoutPanelLeft,
	PaintBucket,
	Proportions,
	Ratio,
	Search,
	SquareRoundCorner,
	Type,
	X,
	Copy,
} from 'lucide-react';

/**
 * Internal dependencies.
 */
import { capitalizeFirstLetter } from '@spectra-helpers';

// Get the details of all the classes.
const allClasses = window?.spectra_admin_gs?.json_data || [];

// Simple color variants for category badges.
const badgeVariants = {
	border: '#ec4899', // Pink 500.
	colors: '#a855f7', // Purple 500.
	display: '#6366f1', // Indigo 500.
	filters: '#0ea5e9', // Sky 500.
	typography: '#14b8a6', // Teal 500.
	sizing: '#22c55e', // Green 500.
	spacing: '#eab308', // Yellow 500.
	variables: '#64748b', // Slate 500.
};

const getCategoryIcon = ( current, active ) => {
	// Set a color based on whether it's active or not.
	const colorToUse = current === active ? '#fff' : '#6b7280';

	// Return the required category icon.
	switch ( current ) {
		case 'border':
			return <SquareRoundCorner color={ colorToUse } />;
		case 'colors':
			return <PaintBucket color={ colorToUse } />;
		case 'display':
			return <LayoutPanelLeft color={ colorToUse } />;
		case 'filters':
			return <Blend color={ colorToUse } />;
		case 'typography':
			return <Type color={ colorToUse } />;
		case 'sizing':
			return <Proportions color={ colorToUse } />;
		case 'spacing':
			return <Ratio color={ colorToUse } />;
		default:
			return <Cog color={ colorToUse } />;
	}
};

// Convert a slug like "background--primary-dark--20" to readable words.
const toWords = ( slug ) => slug.split( '--' ).map( ( part ) => part.replace( /-/g, ' ' ) ).join( ' ' );
// Helper to build the formatted class data with subtext, help text and tags.
const formatClasses = ( classes ) => (
	classes.map( ( item ) => {
		const clean = item.name.replace( /\[.*?\]/g, '' );
		const tokens = clean.split( '--' );
		const main = tokens.shift();
		const subtext = `${ toWords( tokens.join( '--' ) ) } ${ toWords( main ) }`.trim();
		const help = sprintf(
			// Translators: %s is the class name.
			__( 'Use this to apply %s.', 'spectra-pro' ),
			subtext.toLowerCase()
		);
		const tags = Array.isArray( item.tags ) ? item.tags : clean.replace( /--/g, '-' ).split( '-' );
		return {
			...item,
			formattedName: 'variables' === item.category ? `var(--${ item.name })` : `.${ clean }`,
			subtext,
			help,
			tags,
		};
	} )
);

/**
 * Custom Filter Button component that shows an X icon on hover/focus.
 *
 * @param {Object}   props           - Component props.
 * @param {string}   props.content   - Button text content.
 * @param {Function} props.onClick   - Click handler.
 * @param {string}   props.className - Additional CSS classes.
 * @return {Element} The rendered filter button.
 */
const FilterButton = ( { content, onClick, className = '' } ) => {
	const [ isHovered, setIsHovered ] = useState( false );
	const [ isFocused, setIsFocused ] = useState( false );

	const showX = isHovered || isFocused;

	return (
		<Button
			size="xs"
			variant="outline"
			className={ className }
			iconPosition="right"
			icon={ showX ? <X size={ 12 } /> : null }
			destructive={ showX }
			onClick={ onClick }
			onMouseEnter={ () => setIsHovered( true ) }
			onMouseLeave={ () => setIsHovered( false ) }
			onFocus={ () => setIsFocused( true ) }
			onBlur={ () => setIsFocused( false ) }
		>
			{ content }
		</Button>
	);
};

// Helper to copy text to clipboard reliably, with toast notifications
const copyToClipboard = async ( item ) => {
	const isVariable = 'variables' === item.category;
	const text = isVariable ? item.formattedName : item.name;
	const message = isVariable ? __( 'Variable copied to clipboard.', 'spectra-pro' ) : __( 'Class copied to clipboard.', 'spectra-pro' );
	try {
		if ( navigator.clipboard && window.isSecureContext ) {
			await navigator.clipboard.writeText( text );
		} else {
			// fallback for HTTP or older browsers
			const textArea = document.createElement( 'textarea' );
			textArea.value = text;
			textArea.style.position = 'fixed';
			textArea.style.top = 0;
			textArea.style.left = 0;
			textArea.style.width = '2em';
			textArea.style.height = '2em';
			textArea.style.padding = 0;
			textArea.style.border = 'none';
			textArea.style.outline = 'none';
			textArea.style.boxShadow = 'none';
			textArea.style.background = 'transparent';
			document.body.appendChild( textArea );
			textArea.focus();
			textArea.select();
			try {
				document.execCommand( 'copy' );
			} catch ( err ) {
				throw err;
			}
			document.body.removeChild( textArea );
		}
		toast.success( __( 'Copied!', 'spectra-pro' ), { description: message } );
	} catch ( err ) {
		toast.error( __( 'Copy failed', 'spectra-pro' ), { description: err?.message || __( 'Could not copy to clipboard.', 'spectra-pro' ) } );
	}
};

/**
 * Renders the CheatSheet tab.
 *
 * @return {Element} The rendered cheat sheet page.
 */
const CheatSheet = () => {
	const formattedClasses = useMemo( () => formatClasses( allClasses ), [] );
	const categories = useMemo( () => Array.from( new Set( formattedClasses.map( ( c ) => c.category ) ) ), [ formattedClasses ] );
	const [ search, setSearch ] = useState( '' );
	const [ activeCategory, setActiveCategory ] = useState( '' );
	const [ activeTags, setActiveTags ] = useState( [] );
	const BATCH_SIZE = 100;
	const [ currentPage, setCurrentPage ] = useState( 1 );
	const filtered = useMemo( () => formattedClasses.filter( ( item ) => {
		if ( activeCategory && item.category !== activeCategory ) return false;
		if ( activeTags.length && ! activeTags.every( ( t ) => item.tags.includes( t ) ) ) return false;
		if ( search ) {
				const str = `${ item.formattedName } ${ item.subtext } ${ item.help } ${ item.tags.join( ' ' ) } ${ item.category }`;
				if ( -1 === str.toLowerCase().indexOf( search.toLowerCase() ) ) return false;
		}
		return true;
	} ), [ search, activeCategory, activeTags, formattedClasses ] );

	useEffect( () => {
		setCurrentPage( 1 );
	}, [ search, activeCategory, activeTags ] );

	const totalPages = useMemo( () => Math.ceil( filtered.length / BATCH_SIZE ), [ filtered ] );

	const visibleItems = useMemo( () => filtered.slice( ( currentPage - 1 ) * BATCH_SIZE, currentPage * BATCH_SIZE ), [ filtered, currentPage ] );

	const getPageNumbers = () => {
		const pages = [];
		if ( totalPages <= 7 ) {
			for ( let i = 1; i <= totalPages; i++ ) {
				pages.push( i );
			}
		} else if ( currentPage <= 3 || currentPage >= totalPages - 2 ) {
			pages.push( 1, 2, 3, 'ellipsis', totalPages - 2, totalPages - 1, totalPages );
		} else {
			pages.push( 1, 'ellipsis', currentPage - 1, currentPage, currentPage + 1, 'ellipsis', totalPages );
		}
		return pages;
	};

	const toggleTag = ( tag ) => {
		setActiveTags( ( prev ) => prev.includes( tag ) ? prev.filter( ( t ) => t !== tag ) : [ ...prev, tag ] );
	};

	return (
		<>
			<Toaster position="top-right" design="stack" theme="dark" autoDismiss={ true } dismissAfter={ 2000 } />
			<Container direction="row" containerType='grid' cols={ { sm: 1, md: 3, lg: 4 } }>
				{/* The left side container - The Cheatsheet. */}
				<Container.Item colSpan={ { sm: 1, md: 2, lg: 3 } } className="flex gap-6 flex-col w-full mx-auto h-full pt-8 px-4" >
					<Title
						className="[&_h2]:text-text-primary text-xl"
						size="md"
						title={ __( 'Cheatsheet', 'spectra-pro' ) }
					/>
					<Container className="bg-background-primary w-full rounded-xl shadow-sm sm:p-6 p-3 mr-3" direction="column" gap="sm">
						{/* The area for active tags or search results. */}
						{ ( search || activeTags?.length ) ? (
							<Container.Item className="flex gap-2 flex-wrap mb-4">
								{ search && (
									<FilterButton
										onClick={ () => setSearch( '' ) }
										content={ sprintf(
											// translators: %s: The search term from the user.
											__( 'Search: %s', 'spectra-pro' ),
											search
										) }
									/>
								) }
								{ activeTags.map( ( t ) => (
									<FilterButton
										key={ `tag-${ t }` }
										onClick={ () => toggleTag( t ) }
										content={ t }
									/>
								) ) }
							</Container.Item>
						) : ( <></> ) }
						{/* The visible cheatsheet entries. */}
						{ visibleItems.map( ( item, index ) => (
							<div
								key={ `card-${ index }` }
								className="flex flex-col gap-2"
							>
								<div className="flex items-center justify-between gap-2">
									<div className="flex items-center gap-2">
										<code className="font-semibold rounded-md px-3 py-2 text-brand-primary-600 bg-brand-background-50">
											{ item.formattedName }
										</code>
										<span 
											className='rounded-full text-white px-3 py-2 font-semibold'
											style={ {
												background: badgeVariants[ item.category ],
											} }
										>
											{ capitalizeFirstLetter( item.category ) }
										</span>
									</div>
									<Button
										variant="outline"
										size="sm"
										icon={ <Copy size={16} /> }
										aria-label={ __( 'Copy', 'spectra-pro' ) }
										onClick={ () => copyToClipboard( item ) }
									/>
								</div>
								<Label className="font-semibold mb-1" size="md" tag="p">{ item?.title || item.subtext }</Label>
								<Label variant="help" className="block italic text-xs mb-2">{ item.description }</Label>
								<div className="flex gap-2 flex-wrap">
									{ item.tags.map( ( tag ) => (
										<Button
											key={ `card-${ index }-tag-${ tag }` }
											size="xs"
											variant="outline"
											className="bg-gray-50 text-secondary"
											onClick={ () => toggleTag( tag ) }
										>
											{ tag }
										</Button>
									) ) }
								</div>
								{ index !== visibleItems.length - 1 && (
									<hr className="pt-4" style={ { border: 'none', borderBottom: '1px solid #e5e7eb' } }/>
								) }
							</div>
						) ) }
						{/* The pagination. */}
						{ totalPages > 1 && (
							<Container.Item alignSelf={ { sm: 'center', md: 'end', lg: 'end' } } className="flex gap-2 mt-4 flex-wrap">
								<Button
									variant="outline"
									size="sm"
									onClick={ () => setCurrentPage( ( p ) => Math.max( p - 1, 1 ) ) }
									disabled={ 1 === currentPage }
								>
									{ __( 'Prev', 'spectra-pro' ) }
								</Button>
								{ getPageNumbers().map( ( page, index ) => (
									'ellipsis' === page ? (
										<span key={ `ellipsis-${ index }` } className="px-2">&hellip;</span>
									) : (
										<Button
											key={ `page-${ page }` }
											variant={ currentPage === page ? 'primary' : 'outline' }
											size="sm"
											onClick={ () => setCurrentPage( page ) }
										>
											{ page }
										</Button>
									)
								) ) }
								<Button
									variant="outline"
									size="sm"
									onClick={ () => setCurrentPage( ( p ) => Math.min( p + 1, totalPages ) ) }
									disabled={ currentPage === totalPages }
								>
									{ __( 'Next', 'spectra-pro' ) }
								</Button>
							</Container.Item>
						) }
					</Container>
				</Container.Item>
				{/* The right side container - The Filters. */}
				<Container.Item className="flex gap-6 flex-col w-full mx-auto h-full pt-8 px-4" >
					<Input
						prefix={ <Search/> }
						size="lg"
						value={ search }
						onChange={ setSearch }
						placeholder={ __( 'Search…', 'spectra-pro' ) }
					/>
					<div className="flex flex-col gap-2 mt-2">
						{ categories.map( ( cat ) => (
							<Button
								key={ `category-${ cat }` }
								size="lg"
								className="justify-start gap-2 py-2"
								icon={ getCategoryIcon( cat, activeCategory ) }
								variant={ activeCategory === cat ? 'primary' : 'ghost' }
								onClick={ () => setActiveCategory( activeCategory === cat ? '' : cat ) }
							>
								{ capitalizeFirstLetter( cat ) }
							</Button>
						) ) }
					</div>
				</Container.Item>
			</Container>
		</>
	);
};

export default CheatSheet;
