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

import {
	useContext,
} from '@wordpress/element'

import {
	ColorIndicatorContext,
} from '@ska/components'

import {
	TailwindFeatureContext,
	Radio,
	type RadioProps,
} from '..'

import Opacity from './Opacity'

import {
	parseVariantValue,
} from '../../classNames'

import {
	useSkaBlocks,
} from '../../hooks'

import {
	useColorWithOptions,
} from '../../colors'

import type {
	ControlProps,
} from '.'

/** Don't use `-500` suffix for color palette color. */
const STRIP_500 = false

const Color: React.FC<ControlProps> = ({
	label,
	controls,
	supports,
	variant,
	valueKey,
	value: inputValue = '',
	arbitraryValues = [],
	dispatch,
}) => {

	const {
		id,
		getOptions,
	} = useContext(TailwindFeatureContext)

	const options = getOptions(arbitraryValues)

	const {
		parser,
		compiler: {
			resolveColorValue: transformColorValue,
		},
	} = useSkaBlocks()

	const {
		withPrefixSuffix,
		cleanValue: colorValue,
		toggleImportant,
	} = parseVariantValue(inputValue)

	const {
		color,
		basicColorOptions,
		themeColorOptions,
		paletteColorOptions,
		themeColors,
		paletteColors,
	} = useColorWithOptions(colorValue, options)

	const {
		isNonColor,
		isTheme,
		isPalette,
		value,
		valueWithoutOpacity,
		palette,
		modifier: colorModifier,
		opacity,
	} = color

	const onChange: RadioProps['onChange'] = nextValue => {

		if(!nextValue) {
			dispatch.setVariantValue({feature: id, variant, key: valueKey, value: ''})
			return
		}

		const {
			withPrefixSuffix,
			cleanValue,
		} = parseVariantValue(nextValue)

		const valueIncludesOpacity = cleanValue.indexOf(`/${opacity}`) !== -1
		const opacityToAppend = valueIncludesOpacity ? '' : `/${opacity}`

		const {
			palette: nextPalette,
			modifier: nextModifier,
			isTheme,
			isPalette,
			isNonColor,
		} = parser.parseColor(`${cleanValue}${opacity === 101 ? `` : opacityToAppend}`)

		/** Keep current color modifier if the next palette also has it. */
		let keepModifier = ''
		if(
			isTheme
			&& palette !== nextPalette
			&& colorModifier !== 'DEFAULT'
			&& nextModifier === 'DEFAULT'
			&& Object.keys(themeColors.get(nextPalette) || {}).includes(colorModifier)
		) {
			keepModifier = `-${colorModifier}`
		}
		if(
			isPalette
			&& palette !== nextPalette
			&& colorModifier !== '500'
			&& nextModifier === '500'
			&& Object.keys(paletteColors.get(nextPalette) || {}).includes(colorModifier)
		) {
			keepModifier = `-${colorModifier}`
		}

		if(isPalette && !STRIP_500 && !keepModifier && cleanValue.indexOf('-') === -1) {
			keepModifier = `-500`
		}

		const keepOpacity = opacity === 101 || isNonColor ? '' : opacityToAppend
		dispatch.setVariantValue({feature: id, variant, key: valueKey, value: withPrefixSuffix(`${cleanValue}${keepModifier}${keepOpacity}`)})
	}

	const showOpacity = !!value && !isNonColor

	return <>
		<ColorIndicatorContext.Provider value={{transformColorValue}}>
			<Radio.Optimistic
				label={label}
				hideLabelFromVision={controls.length < 2}
				pills
				isSmall
				supports={supports}
				options={basicColorOptions}
				arbitraryValues={arbitraryValues}
				toggleImportant={toggleImportant}
				value={withPrefixSuffix((isTheme || isPalette) ? palette : valueWithoutOpacity)}
				onChange={onChange}
				onAdd={valueToAdd => {
					dispatch.batch([
						dispatch.actions.addArbitraryValue({feature: id, value: valueToAdd}),
						...(value !== valueToAdd ? [
							dispatch.actions.setVariantValue({feature: id, variant, key: valueKey, value: valueToAdd}),
						] : []),
					])
				}}
				onUpdate={(nextValue, prevValue) => {
					dispatch.updateArbitraryValue({feature: id, nextValue, prevValue})
				}}
				onRemove={valueToRemove => {
					dispatch.removeArbitraryValue({feature: id, value: valueToRemove})
				}}
			/>
			{isTheme && (
				<Radio.Optimistic
					key={palette}
					label={sprintf(_x('%s modifier', 'Color palette color name', 'ska-blocks'), upperFirst(palette))}
					pills
					isSmall
					supports={{...supports, important: false}}
					options={themeColorOptions}
					arbitraryValues={arbitraryValues}
					value={`${palette}-${colorModifier}`}
					onChange={nextValue => {
						if(!nextValue) {
							if(colorModifier !== 'DEFAULT') {
								onChange(withPrefixSuffix(palette))
							}
						} else {
							onChange(withPrefixSuffix(nextValue.replace('-DEFAULT', '')))
						}
					}}
				/>
			)}
			{isPalette && (
				<Radio.Optimistic
					key={palette}
					label={sprintf(_x('%s modifier', 'Color palette color name', 'ska-blocks'), upperFirst(palette))}
					pills
					isSmall
					supports={{...supports, important: false}}
					options={paletteColorOptions}
					arbitraryValues={arbitraryValues}
					value={`${palette}-${colorModifier}`}
					onChange={nextValue => {
						if(!nextValue) {
							if(colorModifier !== '500') {
								onChange(withPrefixSuffix(palette))
							}
						} else {
							onChange(withPrefixSuffix(STRIP_500 ? nextValue.replace('-500', '') : nextValue))
						}
					}}
				/>
			)}
		</ColorIndicatorContext.Provider>
		{showOpacity && (
			<Opacity
				value={opacity}
				rawValue={transformColorValue(valueWithoutOpacity)}
				onChange={nextOpacity => {
					const nextValue = nextOpacity === 101 ? valueWithoutOpacity : `${valueWithoutOpacity}/${nextOpacity}`
					dispatch.setVariantValue({feature: id, variant, key: valueKey, value: withPrefixSuffix(nextValue), toggle: false})
				}}
			/>
		)}
	</>
}

export default Color
