import React, {useEffect, useMemo, useRef, useState} from 'react';
import {BrowserMultiFormatReader, ChecksumException, FormatException, NotFoundException} from "@zxing/library";
import {Icon, Modal, Spinner} from "@wordpress/components";
import type {FieldProps} from "./Field";
import {closeSmall} from "@wordpress/icons";
import {__} from "@wordpress/i18n";

type ScannerProps = FieldProps & {
	attrs: Record<string, string>
	onResult: (val: string) => void;
	onError: (err: string) => void;
}

function VideoAppend({isOpen, element}: { isOpen: boolean; element: HTMLVideoElement }) {

	const divRef = useRef<HTMLDivElement | null>(null);

	useEffect(() => {
		if (!isOpen) {
			return;
		}
		const videoElement = element;
		videoElement.autoplay = false;
		videoElement.muted = true;
		videoElement.playsInline = true;
		videoElement.classList.add('hulk-video');
		divRef.current?.appendChild(videoElement);
	}, [element, isOpen]);

	return <div ref={divRef}/>
}


const Scanner = (props: ScannerProps) => {

	const codeReader = useRef(new BrowserMultiFormatReader());
	const videoRef = useRef<HTMLVideoElement>(document.createElement("video"));
	const [isOpen, setOpen] = useState(false);
	const openModal = () => setOpen(true);
	const closeModal = () => {
		codeReader.current.reset();
		setOpen(false);
	};
	const [loading, setLoading] = useState(false);

	const icon = useMemo(() => decodeURIComponent(props.icon), [props.icon]);

	const handleIcon = async (e: React.MouseEvent<HTMLButtonElement>) => {
		e.preventDefault();
		if (!props.freemius.can_use_premium_code) {
			return;
		}
		setLoading(true);
		try {
			const videoInputDevices = await codeReader.current.listVideoInputDevices();
			if (videoInputDevices.length === 0) {
				props.onError(__('No camera found.', 'advanced-fields-for-elementor-forms'));
				return;
			}
			// Find the back camera
			const backCamera = videoInputDevices
				.find(device => device.label.toLowerCase().includes('back'));
			const firstDeviceId = backCamera?.deviceId || videoInputDevices?.[0]?.deviceId;
			await codeReader.current.decodeFromVideoDevice(
				firstDeviceId,
				videoRef.current,
				(decodedResult, decodeError) => {
					if (decodedResult) {
						closeModal();
						props.onResult(decodedResult.getText());
					}
					if (decodeError) {
						if (
							decodeError instanceof NotFoundException ||
							decodeError instanceof ChecksumException ||
							decodeError instanceof FormatException
						) {
							// Ignore these while scanning
							return;
						}
						// Only unexpected errors
						props.onError(decodeError?.message || JSON.stringify(decodeError));
						console.error(decodeError);
					}
				}
			);
			openModal();
		} catch (err: any) {
			codeReader.current.reset();
			props.onError(err?.message || JSON.stringify(err));
		} finally {
			setLoading(false);
		}
	};

	return (
		<>
			{isOpen && (
				<Modal
					className={'hulk-ffef-barcode-field-model'}
					onRequestClose={closeModal}
					__experimentalHideHeader={true}
					shouldCloseOnClickOutside={false}
					size={'large'}
				>
					<button type={'button'} className={'hulk-close'} onClick={closeModal}>
						<Icon icon={closeSmall} size={34}/>
					</button>
					<VideoAppend
						isOpen={isOpen}
						element={videoRef.current}
					/>
					<div className="hulk-overlay">
						<div className="absolute inset-0 z-10 hulk-decorators">
							<div
								className="absolute w-[1.5rem] h-[1.5rem] rounded top-0 left-0 !border-l-4 !border-t-4 rounded-tr-none rounded-bl-none"></div>
							<div
								className="absolute w-[1.5rem] h-[1.5rem] rounded top-0 right-0 !border-r-4 !border-t-4 rounded-tl-none rounded-br-none"></div>
							<div
								className="absolute w-[1.5rem] h-[1.5rem] rounded bottom-0 left-0 !border-l-4 !border-b-4 rounded-tl-none rounded-br-none"></div>
							<div
								className="absolute w-[1.5rem] h-[1.5rem] rounded bottom-0 right-0 !border-r-4 !border-b-4 rounded-tr-none rounded-bl-none"></div>
						</div>
						<div className="hulk-laser"></div>
					</div>
				</Modal>
			)}
			{loading ? (
				<div className="hulk-spinner"><Spinner/></div>
			) : (
				<button
					type={'button'}
					className={'hulk-icon'}
					dangerouslySetInnerHTML={{__html: icon}}
					onClick={handleIcon}
				/>
			)}
		</>
	);
};

export default Scanner;
