import LogDetail from 'components/LogDetail';
import { ColumnTypeRender } from 'components/Logs/TableView/types';
import { useTableView } from 'components/Logs/TableView/useTableView';
import { LOCALSTORAGE } from 'constants/localStorage';
import LogsExplorerContext from 'container/LogsExplorerContext';
import { useActiveLog } from 'hooks/logs/useActiveLog';
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
import { useIsDarkMode } from 'hooks/useDarkMode';
import useDragColumns from 'hooks/useDragColumns';
import { getDraggedColumns } from 'hooks/useDragColumns/utils';
import {
	cloneElement,
	forwardRef,
	memo,
	ReactElement,
	ReactNode,
	useCallback,
	useMemo,
} from 'react';
import {
	TableComponents,
	TableVirtuoso,
	TableVirtuosoHandle,
} from 'react-virtuoso';
import { ILog } from 'types/api/logs/log';

import { infinityDefaultStyles } from './config';
import { LogsCustomTable } from './LogsCustomTable';
import {
	TableCellStyled,
	TableHeaderCellStyled,
	TableRowStyled,
} from './styles';
import { InfinityTableProps } from './types';

// eslint-disable-next-line react/function-component-definition
const CustomTableRow: TableComponents<ILog>['TableRow'] = ({
	children,
	context,
	...props
}) => {
	const { isHighlighted } = useCopyLogLink(props.item.id);

	const isDarkMode = useIsDarkMode();

	return (
		<TableRowStyled
			$isDarkMode={isDarkMode}
			$isActiveLog={isHighlighted}
			// eslint-disable-next-line react/jsx-props-no-spreading
			{...props}
		>
			{children}
		</TableRowStyled>
	);
};

const InfinityTable = forwardRef<TableVirtuosoHandle, InfinityTableProps>(
	function InfinityTableView(
		{ isLoading, tableViewProps, infitiyTableProps },
		ref,
	): JSX.Element | null {
		const {
			activeLog: activeContextLog,
			onSetActiveLog: handleSetActiveContextLog,
			onClearActiveLog: handleClearActiveContextLog,
		} = useActiveLog();
		const {
			activeLog,
			onSetActiveLog,
			onClearActiveLog,
			onAddToQuery,
		} = useActiveLog();

		const { dataSource, columns } = useTableView({
			...tableViewProps,
			onClickExpand: onSetActiveLog,
			onOpenLogsContext: handleSetActiveContextLog,
		});
		const { draggedColumns, onDragColumns } = useDragColumns<
			Record<string, unknown>
		>(LOCALSTORAGE.LOGS_LIST_COLUMNS);

		const isDarkMode = useIsDarkMode();

		const tableColumns = useMemo(
			() => getDraggedColumns<Record<string, unknown>>(columns, draggedColumns),
			[columns, draggedColumns],
		);

		const handleDragEnd = useCallback(
			(fromIndex: number, toIndex: number) =>
				onDragColumns(tableColumns, fromIndex, toIndex),
			[tableColumns, onDragColumns],
		);

		const itemContent = useCallback(
			(index: number, log: Record<string, unknown>): JSX.Element => (
				<>
					{tableColumns.map((column) => {
						if (!column.render) return <td>Empty</td>;

						const element: ColumnTypeRender<Record<string, unknown>> = column.render(
							log[column.key as keyof Record<string, unknown>],
							log,
							index,
						);

						const elementWithChildren = element as Exclude<
							ColumnTypeRender<Record<string, unknown>>,
							ReactNode
						>;

						const children = elementWithChildren.children as ReactElement;
						const props = elementWithChildren.props as Record<string, unknown>;

						return (
							<TableCellStyled
								$isDragColumn={false}
								$isDarkMode={isDarkMode}
								key={column.key}
							>
								{cloneElement(children, props)}
							</TableCellStyled>
						);
					})}
				</>
			),
			[tableColumns, isDarkMode],
		);

		const tableHeader = useCallback(
			() => (
				<tr>
					{tableColumns.map((column) => {
						const isDragColumn = column.key !== 'expand';

						return (
							<TableHeaderCellStyled
								$isDarkMode={isDarkMode}
								$isDragColumn={isDragColumn}
								key={column.key}
								// eslint-disable-next-line react/jsx-props-no-spreading
								{...(isDragColumn && { className: 'dragHandler' })}
							>
								{column.title as string}
							</TableHeaderCellStyled>
						);
					})}
				</tr>
			),
			[tableColumns, isDarkMode],
		);

		return (
			<>
				<TableVirtuoso
					ref={ref}
					style={infinityDefaultStyles}
					data={dataSource}
					components={{
						// eslint-disable-next-line react/jsx-props-no-spreading
						Table: LogsCustomTable({ isLoading, handleDragEnd }),
						// TODO: fix it in the future
						// eslint-disable-next-line @typescript-eslint/ban-ts-comment
						// @ts-ignore
						TableRow: CustomTableRow,
					}}
					itemContent={itemContent}
					fixedHeaderContent={tableHeader}
					totalCount={dataSource.length}
					// eslint-disable-next-line react/jsx-props-no-spreading
					{...(infitiyTableProps?.onEndReached
						? { endReached: infitiyTableProps.onEndReached }
						: {})}
				/>

				{activeContextLog && (
					<LogsExplorerContext
						log={activeContextLog}
						onClose={handleClearActiveContextLog}
					/>
				)}
				<LogDetail
					log={activeLog}
					onClose={onClearActiveLog}
					onAddToQuery={onAddToQuery}
					onClickActionItem={onAddToQuery}
				/>
			</>
		);
	},
);

export default memo(InfinityTable);
