import { useEffect, useState, useMemo } from "react";

import { useLoadingContext } from "@/contexts/loading/lib/useLoadingContext";
import { useGetReportList } from "@/contracts/reports";

const ROWS_PER_PAGE = 8;
const SIBLING_COUNT = 1; // Количество страниц, отображаемых по бокам от текущей (e.g., if 1, shows current-1, current, current+1)
const BOUNDARY_COUNT = 1; // Количество страниц, отображаемых в начале и конце (e.g., if 1, shows page 1 and last page)

export function useReportList() {
	const [currentPage, setCurrentPage] = useState(0); // Начинаем с 0-based index для удобства расчетов
	const [searchTerm, setSearchTerm] = useState("");
	const [sorting, setSorting] = useState<
		"byDateFront" | "byDateBack" | "byNameFront" | "byNameBack" | undefined
	>("byDateBack");
	const { setIsLoading } = useLoadingContext();
	const [total, setTotal] = useState(0);

	const {
		data: reports,
		refetch,
		isFetching,
	} = useGetReportList({
		Skip: currentPage * ROWS_PER_PAGE,
		Take: ROWS_PER_PAGE,
		Search: searchTerm,
		ByDate:
			sorting === "byDateFront"
				? "asc"
				: sorting === "byDateBack"
					? "desc"
					: undefined,
		Alphabetic:
			sorting === "byNameFront"
				? "asc"
				: sorting === "byNameBack"
					? "desc"
					: undefined,
	});

	useEffect(() => {
		setIsLoading(isFetching);
	}, [isFetching, setIsLoading]);

	useEffect(() => {
		refetch().then((response) => {
			setTotal(response?.data?.total || 0);
			const newLastPage = calculateLastPage(response?.data?.total || 0);
			if (currentPage >= newLastPage && newLastPage > 0) {
				setCurrentPage(newLastPage - 1);
			} else if (newLastPage === 0 && currentPage !== 0) {
				setCurrentPage(0);
			}
		});
	}, [currentPage, searchTerm, sorting, refetch]);

	const calculateLastPage = (totalItems = total) => {
		return Math.max(1, Math.ceil((totalItems || 0) / ROWS_PER_PAGE));
	};

	const lastPage = useMemo(() => calculateLastPage(), [total]);

	const isFirstEnabled = currentPage > 0 && total > 0;
	const isPreviousEnabled = currentPage > 0 && total > 0;
	const isNextEnabled = currentPage < lastPage - 1 && total > 0;
	const isLastEnabled = currentPage < lastPage - 1 && total > 0;

	const paginationPages = useMemo(() => {
		const totalPages = lastPage; // Общее количество страниц (1-based)

		if (totalPages <= 1) {
			return []; // Если 0 или 1 страница, пагинация не нужна
		}

		// Вспомогательная функция для генерации диапазона чисел
		const range = (start: number, end: number) => {
			const length = end - start + 1;
			return Array.from({ length }, (_, i) => start + i);
		};

		const pages: (number | "ellipsis")[] = [];

		// 1. Pages for start boundary
		const startBoundaryPages = range(
			0,
			Math.min(BOUNDARY_COUNT - 1, totalPages - 1),
		);
		pages.push(...startBoundaryPages);

		// 2. Sibling pages around current page
		// Calculate the range of sibling pages (exclusive of boundary pages)
		const startSibling = Math.max(
			BOUNDARY_COUNT, // Ensure we don't overlap with start boundary
			currentPage - SIBLING_COUNT,
		);
		const endSibling = Math.min(
			totalPages - 1 - BOUNDARY_COUNT, // Ensure we don't overlap with end boundary
			currentPage + SIBLING_COUNT,
		);

		const siblingPages = range(startSibling, endSibling);

		// 3. Pages for end boundary
		const endBoundaryPages = range(
			Math.max(0, totalPages - BOUNDARY_COUNT),
			totalPages - 1,
		);

		// Combine all unique pages
		const allUniquePages = new Set<number>();
		startBoundaryPages.forEach((p) => allUniquePages.add(p));
		siblingPages.forEach((p) => allUniquePages.add(p));
		endBoundaryPages.forEach((p) => allUniquePages.add(p));

		const sortedUniquePages = Array.from(allUniquePages).sort(
			(a, b) => a - b,
		);

		// Construct final pages array with ellipses
		const finalPages: (number | "ellipsis")[] = [];
		for (let i = 0; i < sortedUniquePages.length; i++) {
			const pageNum = sortedUniquePages[i];
			finalPages.push(pageNum);

			if (i < sortedUniquePages.length - 1) {
				const nextPageNum = sortedUniquePages[i + 1];
				// If there's a gap of more than one page, add an ellipsis
				if (nextPageNum > pageNum + 1) {
					finalPages.push("ellipsis");
				}
			}
		}

		// Final cleaning: remove redundant ellipses or ensure ellipses are where they should be
		const result: (number | "ellipsis")[] = [];
		let lastElement: number | "ellipsis" | null = null;

		for (const item of finalPages) {
			if (item === "ellipsis") {
				// Prevent consecutive ellipses
				if (lastElement === "ellipsis") {
					continue;
				}

				// Prevent ellipsis if it's directly next to a number where no gap exists
				const lastNumBeforeEllipsis =
					typeof lastElement === "number" ? lastElement : null;
				const nextItemIndex = finalPages.indexOf(item) + 1;
				const nextNumAfterEllipsis =
					typeof finalPages[nextItemIndex] === "number"
						? (finalPages[nextItemIndex] as number)
						: null;

				if (
					lastNumBeforeEllipsis !== null &&
					nextNumAfterEllipsis !== null &&
					nextNumAfterEllipsis === lastNumBeforeEllipsis + 1
				) {
					continue;
				}
			}
			result.push(item);
			lastElement = item;
		}

		return result;
	}, [currentPage, lastPage]);

	function toPage(page: number) {
		if (page < 0 || page >= lastPage) {
			return;
		}
		setCurrentPage(page);
	}

	function toFirstPage() {
		setCurrentPage(0);
	}

	function toPreviousPage() {
		if (currentPage === 0) {
			return;
		}
		setCurrentPage(currentPage - 1);
	}

	function toNextPage() {
		if (currentPage >= lastPage - 1) {
			return;
		}
		setCurrentPage(currentPage + 1);
	}

	function toLastPage() {
		setCurrentPage(lastPage - 1);
	}

	function handleSearch(searchTerm: string) {
		setSearchTerm(searchTerm);
		setCurrentPage(0);
	}

	return {
		isFirstEnabled,
		isPreviousEnabled,
		isNextEnabled,
		isLastEnabled,
		currentPage,
		paginationPages,
		toPage,
		toFirstPage,
		toPreviousPage,
		toNextPage,
		toLastPage,
		handleSearch,
		searchTerm,
		rows: reports?.items,
		total: reports?.total,
		isFetching,
		sorting,
		setSorting,
	};
}
