'use client'

import { CheckedState } from '@radix-ui/react-checkbox'
import { useTranslations } from 'next-intl'
import { useRouter } from 'next/navigation'
import { type ComponentProps, useEffect, useRef, useState } from 'react'

import { Actions, Checkbox, Pagination, Popover } from '@/components/atoms'

import {
	IColumnItem,
	IFilterQuery,
	IPaginationOptions,
	ISortItem,
	SortType
} from '@/types'

import {
	cellStyles,
	filterStyles,
	footerStyles,
	headStyles,
	headStylesWrapper,
	rowStyles,
	sortFilterStyles,
	sortStyles,
	tableStyles,
	tableWrapperStyles,
	theadStyles
} from './Table.styles'

import { Typography } from '../Typography'

import { FilterContent } from './FilterContent'
import { FilterIcon } from './FilterIcon'
import { SortIcon } from './SortIcon'
import { getNotFoundData } from './Table.utils'
import { useStickyHeader } from '@/hooks'
import { addParam, getParam, getRangePagination, removeParam } from '@/utils'

const { Text } = Typography

type TableProps = ComponentProps<'div'> & {
	columns: IColumnItem[]
	dataSource: any[]
	defaultSelection?: number[] | string[]
	onRowSelection?: (ids: string[]) => void
	pagination?: IPaginationOptions & { name?: string }
	getData?: (data: Record<string, any>) => void
	filterQuery?: IFilterQuery
	actions?: boolean
	inModal?: boolean
	isAllChecked?: boolean
}

function Table({
	columns,
	dataSource,
	defaultSelection,
	onRowSelection,
	pagination,
	getData,
	filterQuery,
	actions = false,
	inModal = false,
	isAllChecked = false,
	className
}: TableProps) {
	const tg = useTranslations()
	const t = useTranslations(pagination?.name)
	//
	const scrollRef = useRef<HTMLDivElement>(null)
	const headerRef = useRef<HTMLTableSectionElement>(null)
	//
	useStickyHeader(scrollRef, headerRef)
	//
	const router = useRouter()
	//
	const rangePagination = pagination ? getRangePagination(pagination) : null
	//
	const [sortState, setSortState] = useState<Record<string, SortType>>({})
	const [filterState, setFilterState] = useState<Record<string, boolean>>({})
	const [checkedState, setCheckedState] = useState<Record<string, boolean>>(
		defaultSelection
			? defaultSelection.reduce(
					(acc, id) => {
						acc[id] = true

						return acc
					},
					{} as Record<string, boolean>
				)
			: {}
	)
	//
	useEffect(() => {
		const sort = getParam('sort')

		if (columns?.length) {
			const sorts = sort
				? Object.fromEntries(
						JSON.parse(sort).map(({ column, order }: ISortItem) => {
							return [column, order]
						})
					)
				: {}
			//
			setSortState(
				Object.fromEntries(
					columns.map((d: any) => [d.key, sorts[d.key] || false])
				)
			)
		}

		const filter = getParam('filter')

		if (filter) {
			const filters = Object.entries(JSON.parse(filter)).map(
				([key, value]) => {
					return [key, Boolean(value)]
				}
			)
			//
			setFilterState(Object.fromEntries(filters))
		}
	}, [])
	//
	useEffect(() => {
		if (dataSource?.[0]?.id) {
			setCheckedState(prev => {
				const newState: Record<string, boolean> = {}

				dataSource.forEach((d: any) => {
					newState[d.id] = prev.hasOwnProperty(d.id)
						? prev[d.id]
						: isAllChecked
				})

				const prevKeys = Object.keys(prev).sort()
				const newKeys = Object.keys(newState).sort()

				if (
					prevKeys.length === newKeys.length &&
					prevKeys.every((key, i) => key === newKeys[i]) &&
					prevKeys.every(key => prev[key] === newState[key])
				) {
					return prev
				}

				return newState
			})
		}
	}, [dataSource])
	//
	const allChecked =
		Object.values(checkedState).length &&
		Object.values(checkedState).every(Boolean)
	const someChecked = Object.values(checkedState).some(Boolean)
	const isIndeterminate = someChecked && !allChecked
	//
	const onAllCheckedChange = (checked: boolean) => {
		setCheckedState(prev => {
			const newState = Object.keys(prev).reduce(
				(acc, key) => {
					acc[key] = checked
					return acc
				},
				{} as Record<string, boolean>
			)

			if (onRowSelection) {
				const selectedKeys = Object.keys(newState).filter(
					key => newState[key]
				)
				onRowSelection(selectedKeys)
			}

			return newState
		})
	}
	//
	const onCheckedChange = (id: string, checked: CheckedState) => {
		setCheckedState(prev => {
			const newState = {
				...prev,
				[id]: checked as boolean
			}

			if (onRowSelection) {
				const selectedKeys = Object.keys(newState).filter(
					key => newState[key]
				)
				onRowSelection(selectedKeys)
			}

			return newState
		})
	}
	//
	const onSortChange = (column: any) => {
		const { key } = column
		let order: SortType = false
		//
		const newState = Object.keys(sortState).reduce(
			(acc, i) => {
				if (i === key) {
					if (sortState[i] === false) {
						order = 'asc'
					} else if (sortState[i] === 'asc') {
						order = 'desc'
					} else if (sortState[i] === 'desc') {
						order = false
					}
					acc[i] = order
				} else {
					acc[i] = false
				}

				return acc
			},
			{} as Record<string, SortType>
		)
		//
		setSortState(newState)
		//
		const sort = order ? [{ column: key, order }] : []
		//
		if (order) {
			addParam(router, 'sort', JSON.stringify(sort))
		} else {
			removeParam(router, 'sort')
		}
		//
		setTimeout(() => removeParam(router, 'page'), 350)
		//
		getData?.({
			sort,
			page: 0
		})
	}
	//
	return (
		<div className={className} {...(inModal && { ref: scrollRef })}>
			<div className={tableWrapperStyles}>
				<table className={tableStyles}>
					<colgroup>
						{onRowSelection && <col style={{ width: 42 }} />}
						{/* {columns.map((column: any) => {
							return (
								<col
									key={column.key}
									{...(column.width && {
										style: {
											width: column.width
										}
									})}
								/>
							)
						})} */}
						{actions && <col style={{ width: 80 }} />}
					</colgroup>
					<thead
						className={theadStyles}
						{...(inModal && { ref: headerRef })}
					>
						<tr>
							{onRowSelection && (
								<th className={headStylesWrapper()} scope='col'>
									<div
										className={headStyles({
											type: 'selection'
										})}
										data-type='selection'
									>
										<Checkbox
											checked={allChecked || someChecked}
											onCheckedChange={onAllCheckedChange}
											indeterminate={isIndeterminate}
										/>
									</div>
								</th>
							)}
							{columns.map((column: any, idx: number) => {
								const isLast = idx === columns.length - 1
								//
								return (
									<th
										key={column.key}
										className={headStylesWrapper({
											isLast: isLast && !actions
										})}
										scope='col'
									>
										{column.sort && filterQuery ? (
											<Popover
												trigger={
													<div
														className={headStyles()}
														data-type='default'
													>
														<Text
															strong
															accent
															size={'sm'}
														>
															{column.title}
														</Text>
														<div
															className={
																sortFilterStyles
															}
														>
															<span
																data-type='filter'
																className={filterStyles(
																	{
																		isActive:
																			filterState[
																				column
																					.key
																			]
																	}
																)}
															>
																<FilterIcon
																	type={
																		column.sort
																	}
																/>
															</span>
															<button
																onClick={e => {
																	e.preventDefault()
																	onSortChange(
																		column
																	)
																}}
																data-type='sort'
																className={
																	sortStyles
																}
															>
																<SortIcon
																	state={
																		sortState[
																			column
																				.key
																		]
																	}
																/>
															</button>
														</div>
													</div>
												}
												arrow={false}
												sideOffset={1}
												align='start'
												className='p-4'
											>
												<FilterContent
													column={column}
													getData={getData}
													filterQuery={filterQuery}
													setFilterState={
														setFilterState
													}
												/>
											</Popover>
										) : (
											<div
												className={headStyles()}
												data-type='not-sort'
											>
												<Text strong accent size={'sm'}>
													{column.title}
												</Text>
											</div>
										)}
									</th>
								)
							})}
							{actions && (
								<th
									className={headStylesWrapper()}
									scope='col'
								></th>
							)}
						</tr>
					</thead>
					<tbody>
						{dataSource?.length
							? dataSource.map((dataItem: any, idx: number) => {
									return (
										<tr
											key={dataItem.id || idx}
											className={rowStyles}
										>
											{onRowSelection && (
												<td
													className={cellStyles({
														type: 'selection'
													})}
												>
													<div className='flex items-center'>
														<Checkbox
															checked={
																checkedState[
																	dataItem.id
																]
															}
															onCheckedChange={checked =>
																onCheckedChange(
																	dataItem.id,
																	checked
																)
															}
														/>
													</div>
												</td>
											)}
											{Object.entries(dataItem).map(
												([key, value]) => {
													if (key === 'id') return
													//
													return (
														<td
															key={key}
															className={cellStyles()}
														>
															{value as any}
														</td>
													)
												}
											)}
											{actions && (
												<td
													className={cellStyles({
														type: 'actions'
													})}
												>
													<Actions className='ml-auto' />
												</td>
											)}
										</tr>
									)
								})
							: getNotFoundData(
									columns.length + 2,
									tg('no-data')
								)}
					</tbody>
				</table>
			</div>

			{!inModal && (
				<div className={footerStyles}>
					{pagination && pagination.total > pagination.limit && (
						<>
							<Text muted size={'xs'}>
								{pagination.name
									? t('items', {
											from: rangePagination!.from,
											to: rangePagination!.to,
											total: pagination.total
										})
									: tg('pagination.items', {
											from: rangePagination!.from,
											to: rangePagination!.to,
											total: pagination.total
										})}
							</Text>
							<Pagination
								pagination={pagination}
								getData={getData}
							/>
						</>
					)}
				</div>
			)}
		</div>
	)
}

export { Table }
