import { useCallback, useEffect, useRef, useState } from "react";
import { Document, Page } from "react-pdf";
import "react-pdf/dist/esm/Page/AnnotationLayer.css";
import "react-pdf/dist/esm/Page/TextLayer.css";
import ArrowCircleLeftIcon from "@mui/icons-material/ArrowCircleLeft";
import ArrowCircleRightIcon from "@mui/icons-material/ArrowCircleRight";
import { Box, IconButton } from "@mui/material";
import type {
	CustomTextRenderer,
	OnGetTextSuccess,
} from "node_modules/react-pdf/dist/esm/shared/types";
import { socket } from "../socket";
import { API_HOST } from "../util/api";
import { highlightPattern } from "../util/highlighting";

interface PDFViewerProps {
	pitchBookId: string;
	currentPage?: number;
	onPageChange?: (page: number) => void;
	highlight: { text: string; page: number }[];
	focusHighlight: { text: string; page: number };
}

export default function PDFViewer({
	pitchBookId,
	currentPage,
	onPageChange,
	highlight = [],
	focusHighlight,
}: PDFViewerProps) {
	const [numPages, setNumPages] = useState<number | null>(null);
	const [pageNumber, setPageNumber] = useState(currentPage || 1);
	const [containerWidth, setContainerWidth] = useState<number | null>(null);
	const [pdfKey, setPdfKey] = useState(Date.now());
	const containerRef = useRef<HTMLDivElement>(null);
	const [posHighlight, setPosHighlight] = useState<string[]>([]);
	const [posHighlightFocus, setPosHighlightFocus] = useState<string[]>([]);
	const [textContent, setTextContent] = useState<
		{ posKey: string; text: string; i: number }[]
	>([]);

	const onDocumentLoadSuccess = ({ numPages }: { numPages: number }) => {
		setNumPages(numPages);
	};

	useEffect(() => {
		const updateWidth = () => {
			if (containerRef.current) {
				setContainerWidth(containerRef.current.offsetWidth);
			}
		};

		updateWidth();
		window.addEventListener("resize", updateWidth);
		return () => window.removeEventListener("resize", updateWidth);
	}, []);

	useEffect(() => {
		if (currentPage && currentPage !== pageNumber) {
			setPageNumber(currentPage);
		}
	}, [currentPage, pageNumber]);

	useEffect(() => {
		const handleProgress = (data: { id: number; progress: number }) => {
			if (data.id.toString() === pitchBookId && data.progress === 50) {
				setPdfKey(Date.now());
			}
		};

		socket.on("progress", handleProgress);

		return () => {
			socket.off("progress", handleProgress);
		};
	}, [pitchBookId]);

	const handlePageChange = (newPage: number) => {
		setPageNumber(newPage);
		onPageChange?.(newPage);
	};

	const textRenderer: CustomTextRenderer = useCallback(
		(textItem) => {
			return highlightPattern(
				textItem.str,
				`${textItem.width};${textItem.height};${textItem.transform}`,
				posHighlight,
				posHighlightFocus,
			);
		},
		[posHighlight, posHighlightFocus],
	);

	useEffect(() => {
		const tmpPos: string[] = [];
		const tmpPosHighlight: string[] = [];

		if (textContent.length === 0) {
			setPosHighlight([]);
			setPosHighlightFocus([]);
			return;
		}
		const findTextPositions = (searchText: string): number[] => {
			const positions: number[] = [];
			const normalizedSearch = searchText.toLowerCase().trim();

			textContent.forEach((item, index) => {
				if (item.text.toLowerCase().trim() === normalizedSearch) {
					positions.push(index);
				}
			});

			if (positions.length === 0) {
				let cumulativeText = '';
				const textBoundaries: { start: number; end: number; index: number }[] = [];

				textContent.forEach((item, index) => {
					const start = cumulativeText.length;
					cumulativeText += item.text;
					const end = cumulativeText.length;
					textBoundaries.push({ start, end, index });
				});

				const lowerCumulative = cumulativeText.toLowerCase();
				let searchIndex = lowerCumulative.indexOf(normalizedSearch);

				while (searchIndex !== -1) {
					const endIndex = searchIndex + normalizedSearch.length;

					textBoundaries.forEach(boundary => {
						if (
							(boundary.start <= searchIndex && searchIndex < boundary.end) || // Search starts in this item
							(boundary.start < endIndex && endIndex <= boundary.end) || // Search ends in this item
							(searchIndex <= boundary.start && boundary.end <= endIndex) // This item is completely within search
						) {
							if (!positions.includes(boundary.index)) {
								positions.push(boundary.index);
							}
						}
					});
					searchIndex = lowerCumulative.indexOf(normalizedSearch, searchIndex + 1);
				}
			}
			return positions.sort((a, b) => a - b);
		};
		highlight
			.filter(h => h.page === pageNumber)
			.forEach(highlightItem => {
				const positions = findTextPositions(highlightItem.text);
				positions.forEach(pos => {
					if (pos >= 0 && pos < textContent.length) {
						tmpPos.push(textContent[pos].posKey);
					}
				});
			});

		if (focusHighlight?.page === pageNumber && focusHighlight.text) {
			const positions = findTextPositions(focusHighlight.text);

			positions.forEach(pos => {
				if (pos >= 0 && pos < textContent.length) {
					tmpPosHighlight.push(textContent[pos].posKey);
				}
			});
		}

		setPosHighlight([...new Set(tmpPos)]);
		setPosHighlightFocus([...new Set(tmpPosHighlight)]);
	}, [highlight, focusHighlight, pageNumber, textContent]);

	const onGetTextSuccess: OnGetTextSuccess = useCallback((fullText) => {
		setTextContent(
			fullText.items.map((e, i) => ({
				posKey: `${"width" in e ? e.width : 0};${"height" in e ? e.height : 0};${"transform" in e ? e.transform : ""}`,
				text: "str" in e ? e.str : "",
				i,
			})),
		);
	}, []);

	return (
		<Box
			display="flex"
			flexDirection="column"
			justifyContent="center"
			alignItems="center"
			width="100%"
			height="auto"
		>
			<Box
				ref={containerRef}
				sx={{
					width: "100%",
					height: "auto",
					display: "flex",
					justifyContent: "center",
					alignItems: "center",
				}}
			>
				<Document
					key={pdfKey}
					file={`${API_HOST}/api/pitch_book/${pitchBookId}/download`}
					onLoadSuccess={onDocumentLoadSuccess}
					onLoadError={(error) =>
						console.error("Es gab ein Fehler beim Laden des PDFs:", error)
					}
					onSourceError={(error) => console.error("Ungültige PDF:", error)}
				>
					{containerWidth && (
						<Page
							pageNumber={pageNumber}
							width={containerWidth * 0.98}
							customTextRenderer={textRenderer}
							onGetTextSuccess={onGetTextSuccess}
						/>
					)}
				</Document>
			</Box>
			<Box
				mt={1}
				display="flex"
				alignItems="center"
				justifyContent="center"
				gap={1}
				p={1}
			>
				<IconButton
					disabled={pageNumber <= 1}
					onClick={() => handlePageChange(pageNumber - 1)}
				>
					<ArrowCircleLeftIcon fontSize="large" />
				</IconButton>
				<span>
					{pageNumber} / {numPages}
				</span>
				<IconButton
					disabled={pageNumber >= (numPages || 1)}
					onClick={() => handlePageChange(pageNumber + 1)}
				>
					<ArrowCircleRightIcon fontSize="large" />
				</IconButton>
			</Box>
		</Box>
	);
}
