import React, { useEffect, useRef, useState } from 'react'
import { __ } from '@wordpress/i18n'
import { useForm, useWatch } from 'react-hook-form'
import { languages as countryLanguages } from 'countries-list'
import ChannelInterface from 'Interfaces/ChannelInterface'
import ChannelDropdownComponent from './ChannelDropdownComponent'
import LanguageDropdownComponent from './LanguageDropdownComponent'
import SortDropdownComponent from './SortDropdownComponent'

interface SearchFormProps {
    onSearching?: (formData: SearchFormValues) => void
    feedbackController?: (type: string, message: string) => void
    channels: ChannelInterface[]
}

export interface SearchFormValues {
    search: string
    sort: string
    channel: string
    global: boolean
    /** Comma-separated ISO 639-1 codes; synced to search params as Dailymotion `languages`. */
    language: string
}

const SearchFormComponent = ({ onSearching, feedbackController, channels }: SearchFormProps) => {
    const { register, handleSubmit, control, setValue, getValues } = useForm<SearchFormValues>({
        defaultValues: {
            search: '',
            sort: 'recent',
            channel: '',
            global: false,
            language: '',
        },
    })

    const onSearchingRef = useRef(onSearching)
    const getValuesRef = useRef(getValues)
    onSearchingRef.current = onSearching
    getValuesRef.current = getValues

    const [selectedChannels, setSelectedChannels] = useState<string[]>([])
    const [showSort, setShowSort] = useState(false)
    const [showLanguages, setShowLanguages] = useState(false)
    const [showChannels, setShowChannels] = useState(false)
    const [isLoading, setIsLoading] = useState(true)

    const sortWatch = useWatch({ control, name: 'sort' })
    const channelWatch = useWatch({ control, name: 'channel' })
    const languageWatch = useWatch({ control, name: 'language' })
    const searchWatch = useWatch({ control, name: 'search' })
    const globalWatch = useWatch({ control, name: 'global' })

    const selectedSort = sortWatch || 'recent'
    const appliedLanguageCodes = languageWatch
        ? languageWatch.split(',').map((c) => c.trim()).filter(Boolean)
        : []

    const getSnapshot = (): SearchFormValues => {
        const v = getValuesRef.current()
        return {
            search: v.search ?? '',
            sort: v.sort ?? 'recent',
            channel: v.channel ?? '',
            global: Boolean(v.global),
            language: v.language ?? '',
        }
    }

    const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
    const skipSearchDebounce = useRef(true)

    useEffect(() => {
        if (debounceRef.current) {
            clearTimeout(debounceRef.current)
        }
        debounceRef.current = setTimeout(() => {
            if (skipSearchDebounce.current) {
                skipSearchDebounce.current = false
                return
            }
            onSearchingRef.current?.(getSnapshot())
        }, 500)
        return () => {
            if (debounceRef.current) {
                clearTimeout(debounceRef.current)
            }
        }
    }, [searchWatch])

    useEffect(() => {
        setSelectedChannels(
            channelWatch
                ? channelWatch.split(',').map((id) => id.trim()).filter(Boolean)
                : []
        )
    }, [channelWatch])

    useEffect(() => {
        if (channels.length > 0) {
            const firstId = channels[0].id
            setSelectedChannels([firstId])
            setValue('channel', firstId)
            setIsLoading(false)
            onSearchingRef.current?.({
                search: getValuesRef.current('search') || '',
                sort: getValuesRef.current('sort') || 'recent',
                channel: firstId,
                global: Boolean(getValuesRef.current('global')),
                language: getValuesRef.current('language') || '',
            })
        }
    }, [channels, setValue])

    useEffect(() => {
        const handleClickOutside = (event: MouseEvent) => {
            const target = event.target as Node
            const sortBtn = document.getElementById('sortBtn')
            const ownerBtn = document.getElementById('ownerBtn')
            const languageBtn = document.getElementById('languageBtn')
            const sortWrapper = document.getElementById('sortWrapper')
            const channelsWrapper = document.getElementById('channelsWrapper')
            const languagesWrapper = document.getElementById('languagesWrapper')

            if (
                showSort &&
                sortBtn &&
                sortWrapper &&
                !sortBtn.contains(target) &&
                !sortWrapper.contains(target)
            ) {
                setShowSort(false)
            }

            if (
                showChannels &&
                ownerBtn &&
                channelsWrapper &&
                !ownerBtn.contains(target) &&
                !channelsWrapper.contains(target)
            ) {
                setShowChannels(false)
            }

            if (
                showLanguages &&
                languageBtn &&
                languagesWrapper &&
                !languageBtn.contains(target) &&
                !languagesWrapper.contains(target)
            ) {
                setShowLanguages(false)
            }
        }

        document.addEventListener('mousedown', handleClickOutside)
        return () => {
            document.removeEventListener('mousedown', handleClickOutside)
        }
    }, [showSort, showChannels, showLanguages])

    const submitForm = (formData: SearchFormValues) => {
        onSearching?.(formData)
    }

    const handleSortSelect = (value: string) => {
        setValue('sort', value)
        setShowSort(false)
        onSearching?.({
            ...getSnapshot(),
            sort: value,
        })
    }

    const handleChannelApply = (ids: string[]) => {
        setSelectedChannels(ids)
        setValue('channel', ids.join(','))
        setShowChannels(false)
        onSearching?.({
            ...getSnapshot(),
            channel: ids.join(','),
        })
    }

    const handleLanguageApply = (codes: string[]) => {
        setValue('language', codes.join(','))
        setShowLanguages(false)
        onSearching?.({
            ...getSnapshot(),
            language: codes.join(','),
        })
    }

    const toggleSort = () => {
        setShowChannels(false)
        setShowLanguages(false)
        setShowSort((s) => !s)
    }

    const toggleLanguages = () => {
        setShowSort(false)
        setShowChannels(false)
        setShowLanguages((s) => !s)
    }

    const toggleChannels = () => {
        setShowSort(false)
        setShowLanguages(false)
        setShowChannels((s) => !s)
    }

    const globalField = register('global')

    return (
        <form
            className="action-wrapper sidebar-search__form"
            id="controlMainWrapper"
            onSubmit={handleSubmit(submitForm)}
        >
            <div className="input-group--wrapper input-wrapper" id="searchWrapper" role="group">
                <input
                    type="text"
                    id="search"
                    className="input-form search-input"
                    name="search"
                    placeholder={__('Search Video (e.g. Football)', 'textdomain')}
                    {...register('search')}
                />
                <button
                    className="btn btn-branded btn-icon search-btn"
                    id="searchBtn"
                    type="submit"
                    title={__('Search', 'textdomain')}
                >
                    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden>
                        <path
                            d="M10.1234 5.77502C9.58344 5.77502 9.14844 6.21002 9.14844 6.75002C9.14844 7.29002 9.58344 7.72502 10.1234 7.72502C11.4434 7.72502 12.5234 8.80502 12.5234 10.125C12.5234 10.665 12.9584 11.1 13.4984 11.1C14.0384 11.1 14.4734 10.665 14.4734 10.125C14.4734 7.72502 12.5234 5.77502 10.1234 5.77502ZM20.5034 16.995L16.7534 13.245C17.2034 12.3 17.4734 11.235 17.4734 10.125C17.4734 6.07502 14.1734 2.77502 10.1234 2.77502C6.07344 2.77502 2.77344 6.07502 2.77344 10.125C2.77344 14.175 6.07344 17.475 10.1234 17.475C11.2484 17.475 12.2984 17.205 13.2434 16.755L16.9934 20.505C17.4584 20.97 18.0884 21.225 18.7484 21.225C19.4084 21.225 20.0234 20.97 20.5034 20.505C20.9684 20.04 21.2234 19.41 21.2234 18.75C21.2234 18.09 20.9684 17.475 20.5034 16.995ZM10.1234 15.525C7.13844 15.525 4.72344 13.11 4.72344 10.125C4.72344 7.14002 7.13844 4.72502 10.1234 4.72502C13.1084 4.72502 15.5234 7.14002 15.5234 10.125C15.5234 13.11 13.1084 15.525 10.1234 15.525ZM19.1234 19.125C18.9284 19.32 18.5834 19.32 18.3884 19.125L14.9234 15.66C15.1934 15.435 15.4334 15.18 15.6584 14.925L19.1234 18.39C19.2284 18.495 19.2734 18.615 19.2734 18.765C19.2734 18.915 19.2134 19.035 19.1234 19.14V19.125Z"
                            fill="white"
                        />
                    </svg>
                </button>
            </div>

            {globalWatch && (
                <LanguageDropdownComponent
                    languages={countryLanguages}
                    isOpen={showLanguages}
                    appliedCodes={appliedLanguageCodes}
                    onToggle={toggleLanguages}
                    onApply={handleLanguageApply}
                />
            )}

            {!isLoading && !globalWatch && (
                <ChannelDropdownComponent
                    channels={channels}
                    isOpen={showChannels}
                    appliedIds={selectedChannels}
                    onToggle={toggleChannels}
                    onApply={handleChannelApply}
                />
            )}

            <SortDropdownComponent
                selected={selectedSort}
                isOpen={showSort}
                onToggle={toggleSort}
                onSelect={handleSortSelect}
            />

            <input type="hidden" {...register('sort')} />
            <input type="hidden" {...register('channel')} />
            <input type="hidden" {...register('language')} />

            {!isLoading && (
                <div className="checkbox-group">
                    <input
                        type="checkbox"
                        id="global"
                        {...globalField}
                        onChange={(e) => {
                            globalField.onChange(e)
                            if (e.target.checked) {
                                feedbackController?.(
                                    'feedback-success',
                                    'Global Search <strong>Actived</strong>'
                                )
                            } else {
                                feedbackController?.(
                                    'feedback-success',
                                    'Global Search <strong>Inactived</strong>'
                                )
                            }
                            const checked = e.target.checked
                            queueMicrotask(() => {
                                onSearching?.({
                                    ...getSnapshot(),
                                    global: checked,
                                })
                            })
                        }}
                    />
                    <label htmlFor="global" className="checkbox-label">
                        {__('Global Search', 'textdomain')}
                    </label>
                </div>
            )}
        </form>
    )
}

export default SearchFormComponent
