import * as React from 'react'
import {__, _x} from '@wordpress/i18n'

import {
	useEffect,
	useState,
} from '@wordpress/element'

import {
	Icon,
	Notice,
	Spinner,
	__experimentalVStack as VStack,
} from '@wordpress/components'

import {
	applyFilters,
} from '@wordpress/hooks'

import {
	useQueryClient,
	useQuery,
} from '@tanstack/react-query'

import Fuse from 'fuse.js'

import {
	Search,
	ButtonGroup,
	SearchResult,
} from '@ska/components'

import {
	QueryClientProvider,
	fetchIconCollections,
	fetchIcons,
	fetchIcon,
} from '../../api'

import {
	SKA_ICONS_VER,
} from '../../data'

import './style.scss'

const processSvg = (collection: string, icon: string, svg: string) => {

	let processedSvg = svg

	switch(collection) {
		case 'heroicons':
			processedSvg = processedSvg
				.replaceAll('fill="#0F172A"', 'fill="currentColor"')
				.replaceAll('stroke="#0F172A"', 'stroke="currentColor"')
		break
		case 'font-awesome-6':
			processedSvg = processedSvg.replaceAll('<svg ', '<svg fill="currentColor" ')
		break
	}

	/** When viewBox is present, remove w/h so that Tailwind classes can determine the dimensions. */
	if(svg.includes('viewBox="')) {
		processedSvg = processedSvg
			.replaceAll(' width="', ' data-svg-width="')
			.replaceAll(' height="', ' data-svg-height="')
	}

	return applyFilters('ska.blocks.processSvgIcon', processedSvg, collection, icon) as string
}

const collectionLabel = (value: string) => {

	switch(value) {
		case 'font-awesome-6':
			return _x('FA-6', 'Icon collection label', 'ska-blocks');
		case 'fa-7':
			return _x('FA-7', 'Icon collection label', 'ska-blocks');
		case 'feather':
			return _x('Feather', 'Icon collection label', 'ska-blocks');
		case 'heroicons':
			return _x('Heroicons', 'Icon collection label', 'ska-blocks');
	}

	return value
}

const collectionTooltip = (value: string) => {

	switch(value) {
		case 'font-awesome-6':
			return _x('Font Awesome 6 icons', 'Icon collection tooltip', 'ska-blocks');
		case 'fa-7':
			return _x('Font Awesome 7 icons', 'Icon collection tooltip', 'ska-blocks');
		case 'feather':
			return _x('Feather icons', 'Icon collection tooltip', 'ska-blocks');
		case 'heroicons':
			return _x('Heroicons icons', 'Icon collection tooltip', 'ska-blocks');
	}

	return undefined
}

const ResultIcon: React.FC<{collection: string, icon: string}> = ({collection, icon}) => {

	const {
		isPending,
		data: svg = '',
	} = useQuery({
		queryKey: ['icon', SKA_ICONS_VER, collection, icon],
		queryFn: () => fetchIcon(collection, icon),
		enabled: !!collection && !!icon,
		meta: {persist: true},
	})

	if(isPending) {
		return <Spinner style={{height: '16px', width: '16px', margin: '0'}} />
	}

	return <Icon icon={<><i className='ska-icon-picker__icon-preview' dangerouslySetInnerHTML={{__html: svg}} /></>} />
}

export interface IconPickerProps {
	collection?: string
	icon?: string
	onChange: (nextIcon: {collection: string, icon: string, svg: string}) => void
}

const NO_ICONS = [] as string[]
const FUSE = new Fuse(NO_ICONS)

const IconPicker: React.FC<IconPickerProps> = ({
	collection: currentCollection = '',
	icon = '',
	onChange,
}) => {

	const queryClient = useQueryClient()

	const {
		isPending: loadingCollections,
		data: collections = [],
		status,
		failureReason,
	} = useQuery({
		queryKey: ['collections', SKA_ICONS_VER],
		queryFn: fetchIconCollections,
	})

	const [collection, setCollection] = useState(currentCollection)

	const {
		isPending: loadingIcons,
		data: icons = NO_ICONS,
	} = useQuery({
		queryKey: ['icons', collection],
		queryFn: () => fetchIcons(collection),
		enabled: !!collection,
	})

	useEffect(() => {
		FUSE.setCollection(icons)
	}, [collection, icons])

	const getResults = (searchTerm: string) => {
		return FUSE.search(searchTerm).map(r => r.item).slice(0, 64).map(icon => {
			const parts = (icon as string).split('/')
			const title = parts.pop()
			return {
				id: icon,
				title,
				content: `${[collection, ...parts].join('/')}`,
			} as SearchResult
		})
	}

	const getResultIcon = ({id}: SearchResult) => {
		return (
			<ResultIcon
				key={`${collection}-${id}`}
				collection={collection}
				icon={id as string}
			/>
		)
	}

	const onSelect = async ({id}: SearchResult) => {

		const icon = id as string
		let svgIcon = queryClient.getQueryData(['icon', collection, icon]) as string | undefined

		if(!svgIcon) {
			try {
				svgIcon = await queryClient.fetchQuery({
					queryKey: ['icon', collection, icon],
					queryFn: () => fetchIcon(collection, icon),
				})
			} catch(e) {}
		}

		if(!svgIcon) {
			return
		}

		onChange({
			collection,
			icon,
			svg: processSvg(collection, icon, svgIcon),
		})
	}

	if(loadingCollections) {
		return <Spinner style={{height: '24px', width: '24px', margin: '0 6px'}} />
	}

	if(!collections.length) {

		if(status === 'error') {

			return (
				<Notice
					status='error'
					isDismissible={false}
				>
					<p style={{marginBottom: 6}}><strong>{__('No icon collections available.', 'ska-blocks')}</strong></p>
					{failureReason && <>
						{/* @ts-expect-error */}
						{failureReason?.code && <code>{failureReason.code}</code>}
						{failureReason?.message && <p style={{marginBottom: 0}}>{failureReason.message}</p>}
					</>}
				</Notice>
			)
		}

		return (
			<p>
				{__('No icon collections found. Install the ska-icons plugin:', 'ska-blocks')}
				{' '}
				<a href='https://ska-blocks.com/docs/image-block/#ska-icons-plugin' target='_blank' rel='noopener noreferrer'>/docs/image-block/#ska-icons-plugin</a>
			</p>
		)
	}

	return (
		<VStack className='ska-icon-picker'>
			<ButtonGroup.Radio
				label={__('Icon collection', 'ska-blocks')}
				hideLabelFromVision
				isSmall
				pills
				options={collections.map((value: string) => ({
					label: collectionLabel(value),
					tooltip: collectionTooltip(value),
					value,
				})).sort((a, b) => a.label.localeCompare(b.label))}
				value={collection}
				onChange={value => value && setCollection(value)}
			/>
			{collection && <>
				<Search
					key={collection}
					virtualized
					getResults={getResults}
					onSelect={onSelect}
					getResultIcon={getResultIcon}
					actionInputProps={{
						label: __('Search for an icon', 'ska-blocks'),
						placeholder: currentCollection && currentCollection === collection && icon
							? `${icon}`
							: __('Search icons…', 'ska-blocks'),
						actionLabel: __('Search', 'ska-blocks'),
						loading: loadingIcons,
					}}
				/>
			</>}
		</VStack>
	)
}

const IconPickerComponent: React.FC<IconPickerProps> = props => {
	return (
		<QueryClientProvider>
			<IconPicker {...props} />
		</QueryClientProvider>
	)
}

export default IconPickerComponent
