import { useState, useRef, useEffect, useCallback } from "react";

const focusUrlParamName = 'focus'
const focusChangedEventName = "focus-changed"
const focusedElementClassName = 'focused-element'

function triggerElementFocused(elementKey?: string) {
    const url = new URL(window.location.href);
    if (elementKey) {
        url.searchParams.set(focusUrlParamName, elementKey)
    } else {
        url.searchParams.delete(focusUrlParamName)
    }
    const focusChangeEvent = new Event(focusChangedEventName)
    history.pushState({}, "", url);
    window.dispatchEvent(focusChangeEvent)
}

export function useFocusedElement<ElementType extends HTMLElement>(elementKey: string) {
    const [isFocusedElement, setFocusedElement] = useState(false)
    const focusedClass = isFocusedElement ? focusedElementClassName : ''
    const elementRef = useRef<ElementType>(null)

    const focusElement = useCallback(() => {
        triggerElementFocused(isFocusedElement ? undefined : elementKey)
    }, [isFocusedElement, elementKey])

    useEffect(() => {
        function updateFocusedState() {
            const params = new URLSearchParams(window.location.search)
            const focusedElement = params.get(focusUrlParamName)
            const focused: boolean = focusedElement && focusedElement == elementKey || false
            setFocusedElement(focused)
        }

        updateFocusedState()
        addEventListener(focusChangedEventName, updateFocusedState)
        return () => {
            removeEventListener(focusChangedEventName, updateFocusedState)
        }
    }, [elementKey, setFocusedElement, focusElement])

    isFocusedElement && elementRef.current?.scrollIntoView()

    return {isFocusedElement, focusedClass, elementRef, focusElement}
}

export function useAutoFocus<ElementType extends HTMLElement>(elementKey: string) {
    const {elementRef, focusedClass, focusElement} = useFocusedElement<ElementType>(elementKey);

    useEffect(() => {
        let cleanup = () => {}
        if (elementRef.current) {
            const elem = elementRef.current
            elem.onclick = (evt) => {
                evt.stopPropagation()
                focusElement()
            }
            const classNameBackup = elem.className
            elem.className += ' ' + focusedClass
            cleanup = () => {
                elem.className = classNameBackup
            }
        }
        return cleanup
    }, [elementRef, focusedClass, focusElement])

    return elementRef
}
