'use client'

import { CheckedState } from '@radix-ui/react-checkbox'
import { useTranslations } from 'next-intl'
import { useRouter } from 'next/navigation'
import {
	ChangeEvent,
	Dispatch,
	SetStateAction,
	useEffect,
	useState
} from 'react'
import { DateRange } from 'react-day-picker'

import { Checkbox, Input, Label, Spin } from '@/components/atoms'

import { IFilterQuery } from '@/types'

import { DatePicker } from '../../DatePicker'
import { RangeNumber } from '../../RangeNumber'
import { Typography } from '../../Typography'

import { useDebounce } from '@/hooks'
import { _, addParam, getParam, removeParam } from '@/utils'

const { Link } = Typography

type FilterContentProps = {
	column: any
	getData: any
	filterQuery: IFilterQuery
	setFilterState: Dispatch<SetStateAction<Record<string, boolean>>>
}

function FilterContent({
	column,
	getData,
	filterQuery,
	setFilterState
}: FilterContentProps) {
	const t = useTranslations()
	//
	const router = useRouter()
	//
	const { querykey, queryFn } = filterQuery
	//
	const [q, setQ] = useState<string>()
	const [checkedState, setCheckedState] = useState<Record<string, boolean>>(
		{}
	)
	const [rangeState, setRangeState] = useState<DateRange>()
	const debouncedQ = useDebounce(q, 300)
	//
	const { data, loading, refetch } = queryFn({
		variables: {
			data: {
				column: column.key
			}
		}
	})
	//
	useEffect(() => {
		const filter = getParam('filter')
		const filterValues = filter ? JSON.parse(filter)[column.key] : []
		const isAll = filterValues?.includes('ALL')

		if (data?.[querykey].data.length) {
			if (
				filterValues?.length === 2 &&
				_.isNumber(filterValues?.[0]) &&
				_.isNumber(filterValues?.[1])
			) {
				setRangeState({
					from: new Date(filterValues[0]),
					to: new Date(filterValues[1])
				})
			} else {
				setCheckedState(
					Object.fromEntries(
						data?.[querykey].data.map((item: any) => [
							item.id,
							isAll || filterValues?.includes(item.id)
						])
					)
				)
			}
		}
	}, [data])
	//
	const allChecked =
		Object.values(checkedState).length &&
		Object.values(checkedState).every(Boolean)
	const someChecked = Object.values(checkedState).some(Boolean)
	//
	const onAllCheckedChange = (checked: boolean) => {
		setCheckedState(prev => {
			const newState = Object.keys(prev).reduce(
				(acc, key) => {
					acc[key] = checked
					return acc
				},
				{} as Record<string, boolean>
			)

			return newState
		})

		const oldFilter = getParam('filter')

		const newFilter: Record<string, string[]> = {
			...(oldFilter ? JSON.parse(oldFilter) : {})
		}

		if (checked) {
			newFilter[column.key] = ['ALL']
		} else {
			delete newFilter[column.key]
		}

		if (Object.values(newFilter).some(f => f.length)) {
			addParam(router, 'filter', JSON.stringify(newFilter))
		} else {
			removeParam(router, 'filter')
		}

		setFilterState(prev => {
			prev[column.key] = checked

			return prev
		})

		getData({
			filter: newFilter
		})
	}
	//
	const onCheckedChange = (id: string, checked: CheckedState) => {
		let filterValue: string[] = []
		//
		setCheckedState(prev => {
			const newState = {
				...prev,
				[id]: checked as boolean
			}

			const checkedIds = Object.entries(newState)
				.filter(d => d[1])
				.map(d => d[0])

			filterValue =
				data?.[querykey].data
					.map((item: any) => item.id)
					.filter((id: string) => checkedIds.includes(id)) || []

			return newState
		})

		const oldFilter = getParam('filter')

		const newFilter: Record<string, string[]> = {
			...(oldFilter ? JSON.parse(oldFilter) : {})
		}

		if (filterValue.length) {
			newFilter[column.key] = filterValue
		} else {
			delete newFilter[column.key]
		}

		if (Object.values(newFilter).some(f => f.length)) {
			addParam(router, 'filter', JSON.stringify(newFilter))
		} else {
			removeParam(router, 'filter')
		}

		setFilterState(prev => {
			prev[column.key] = Boolean(filterValue.length)

			return prev
		})

		getData({
			filter: newFilter
		})
	}
	//
	const { sort: type } = column
	//
	const onChangeValue = (value: DateRange) => {
		const oldFilter = getParam('filter')

		const newFilter: Record<string, any> = {
			...(oldFilter ? JSON.parse(oldFilter) : {})
		}

		if (value) {
			newFilter[column.key] = [value.from!.getTime(), value.to!.getTime()]
		} else {
			delete newFilter[column.key]
		}

		if (Object.values(newFilter).some(f => f.length || f.from)) {
			addParam(router, 'filter', JSON.stringify(newFilter))
		} else {
			removeParam(router, 'filter')
		}

		setFilterState(prev => {
			prev[column.key] = Boolean(value)

			return prev
		})

		getData({
			filter: newFilter
		})
	}
	//
	useEffect(() => {
		if (!_.isUndefined(debouncedQ)) {
			refetch({
				data: { column: column.key, q: debouncedQ }
			})
		}
	}, [debouncedQ])
	//
	return (
		<>
			{type === 'number' ? <RangeNumber size={'sm'} /> : null}
			{type === 'date' ? (
				<DatePicker
					size={'sm'}
					mode={'range'}
					onSelect={value => onChangeValue(value!)}
					defaultOpen={{ isOpen: true, delay: 100 }}
					defaultSelected={rangeState}
				/>
			) : null}
			{type === 'string' ? (
				<Input.Search
					value={q || ''}
					onChange={(e: ChangeEvent<HTMLInputElement>) =>
						setQ(e.target.value)
					}
					placeholder={t('search')}
					sizes={'sm'}
				/>
			) : null}
			{type === 'string' ? (
				<>
					<div className='my-3 flex justify-between'>
						<Link
							asChild
							href='#'
							size={'sm'}
							onClick={() => onAllCheckedChange(true)}
							disabled={!!allChecked}
						>
							<button>{t('select-all')}</button>
						</Link>
						<Link
							asChild
							href='#'
							size={'sm'}
							onClick={() => onAllCheckedChange(false)}
							disabled={!someChecked}
						>
							<button>{t('reset')}</button>
						</Link>
					</div>
					<div className='flex flex-col gap-2'>
						{loading ? (
							<Spin />
						) : (
							data?.[querykey].data.map((item: any) => {
								return (
									<Label htmlFor={item.id} key={item.id}>
										<Checkbox
											id={item.id}
											checked={checkedState[item.id]}
											onCheckedChange={checked =>
												onCheckedChange(
													item.id,
													checked
												)
											}
										/>
										{item.value}
									</Label>
								)
							})
						)}
					</div>
				</>
			) : null}
		</>
	)
}

export { FilterContent }
