import {useEffect, useMemo, useRef, useState} from 'react';
import renderHtmlAttributes from "../../utils/renderHtmlAttributes";
import useFormSubmitSuccess from "../../hooks/useFormSubmitSuccess";
import UpgradeOverlay from "../../components/UpgradeOverlay";
import type {FreemiusProps} from "../../types/freemius";

type Option = {
	label: string; value: string, icon: string,
	graphicElement: 'empty' | 'image' | 'icon',
	image: string
}

type FieldProps = {
	itemId: string
	formId: string
	attrs: Record<string, string | string[]>
	value: { [key in string]?: boolean }
	options: Option[]
	isMulti: boolean
	enforced: boolean
	showLabels: boolean
} & FreemiusProps

const Field = (props: FieldProps) => {

	const inputRef = useRef<any>(null);
	const attrs = useMemo(() => renderHtmlAttributes(props.attrs), [props.attrs]);

	const initialValue = useMemo(() => {
		if (!props.isMulti) {
			const firstKey = Object.keys(props.value)?.[0];
			if (firstKey) {
				return {[firstKey]: props.value[firstKey]};
			}
			return {}
		}
		return props.value;
	}, [props.isMulti, props.value]);

	const [value, setValue] = useState<FieldProps['value']>(initialValue);

	// Reset after form submit
	useFormSubmitSuccess(inputRef, () => {
		setValue(initialValue);
	}, [initialValue]);

	const getOptions = useMemo(() => props.options.map(value1 => {
		let icon: string;
		try {
			icon = decodeURIComponent(value1.icon);
		} catch (e) {
			icon = value1.icon;
		}
		return {...value1, icon};
	}), [props.options]);

	function handleChecked(val: string) {
		if (!props.freemius.can_use_premium_code) {
			return;
		}
		setValue(prevState => {
			const data = {...prevState, [val]: false};
			let length = 0;
			if (props.enforced) {
				length = Object
					.entries(data)
					.filter(([, value1]) => value1).length;
			}
			Object.keys(data).forEach(key1 => {
				if (!props.isMulti) {
					data[key1] = false;
				}
				if (props.enforced && length <= 0) {
					data[val] = true;
				} else {
					data[val] = !prevState[val];
				}
			});
			return data;
		});
	}

	const inputValue = useMemo(() => {
		return Object
			.entries(value)
			.filter(([, value1]) => value1 === true)
			.map(([key]) => key)
			.join(',');
	}, [value]);

	useEffect(() => {
		const element = inputRef.current;
		element?.dispatchEvent(new Event('change', {bubbles: true}));
	}, [value]);

	return (
		<>
			{!props.freemius.can_use_premium_code && <UpgradeOverlay url={props.freemius.get_upgrade_url}/>}
			<div className="hulk-image-choices">
				{getOptions.map((item, index) => (
					<Button
						key={`hulk-item-${props.formId}-${props.itemId}-${index}`}
						item={item}
						showLabels={props.showLabels}
						onClick={handleChecked}
						value={value}
					/>
				))}
			</div>
			<input ref={inputRef} {...attrs} type="hidden" defaultValue={inputValue}/>
		</>
	);
};

function Button({item, showLabels, onClick, value}: {
	item: Option,
	showLabels: boolean,
	onClick: (val: string) => void
	value: FieldProps['value']
}) {

	const label = useMemo(() => item.label || item.value, [item.label, item.value]);

	const icon = useMemo(() => {
		switch (item.graphicElement) {
			case 'image':
				return `<img src="${item.image}" alt="${label}">`;
			case "icon":
				return item.icon;
		}
		return '';
	}, [item.graphicElement, item.icon, item.image, label]);

	const isChecked = useMemo(() => {
		const values: Record<string, string> = Object.keys(value).reduce((previousValue, currentValue) => ({
			...previousValue,
			[currentValue?.toLowerCase()]: value[currentValue],
		}), {});
		return !!values[item.value?.toLowerCase() || item.label?.toLowerCase()]
	}, [item.label, item.value, value]);

	return (
		<button
			type="button"
			aria-label={label}
			aria-pressed={isChecked}
			className={'hulk-item-button'}
			onClick={(e) => {
				e.preventDefault();
				onClick(item.value || item.label);
			}}
		>
			{icon && <span className="hulk-item-icon" dangerouslySetInnerHTML={{__html: icon}}/>}
			{(label && showLabels) && <span className="hulk-item-label">{label}</span>}
		</button>
	)
}

export default Field;
