import { keepPreviousData } from "@tanstack/react-query";
import {
	ChevronDown,
	ChevronLeft,
	ChevronRight,
	ChevronsLeft,
	ChevronUp,
	Filter,
	FilterX,
	MapIcon,
	RotateCcwIcon,
	Table,
} from "lucide-react";
import type { GetServerSideProps } from "next";
import Head from "next/head";
import { useEffect, useMemo, useState } from "react";
import { AccordionComp } from "~/components/accordionComp";
import { AnnunciGrid } from "~/components/annunci_grid";
import { MapSection } from "~/components/annunci_map";
import { CTA_TipologiaModal } from "~/components/annunci_tutorial";
import { CodiceBox } from "~/components/codiceRicerca";
import { Layout } from "~/components/Layout";
import { LoadingPage } from "~/components/loading";
import { Status500 } from "~/components/status-page";
import { Badge } from "~/components/ui/badge";
import { Button } from "~/components/ui/button";
import {
	DropdownMenu,
	DropdownMenuContent,
	DropdownMenuTrigger,
} from "~/components/ui/dropdown-menu";
import { Label } from "~/components/ui/label";
import {
	Select,
	SelectContent,
	SelectItem,
	SelectTrigger,
	SelectValue,
} from "~/components/ui/select";
import { cn } from "~/lib/utils";
import { useTranslation } from "~/providers/I18nProvider";
import {
	type AnnunciOptions,
	RicercaProvider,
	type SortTypes,
	useRicerca,
} from "~/providers/RicercaProvider";
import { generateSSGHelper } from "~/server/utils/ssgHelper";
import { api } from "~/utils/api";

type AnnunciPageProps = {
	options: AnnunciOptions;
};

const Annunci = ({ options }: AnnunciPageProps) => {
	const { t } = useTranslation();

	return (
		<RicercaProvider options={options}>
			<Head>
				<title>{t.heads.annunci_titolo}</title>
				<meta content={t.heads.annunci_description} name="description" />
			</Head>

			<main className="relative mx-auto w-full max-w-7xl space-y-5 bg-background2 px-2 py-5 md:px-8">
				<div className="inline-block rounded-md bg-accent px-3 py-1 text-primary text-sm outline outline-neutral-500">
					{t.annunci.titolo}
				</div>

				<GoBackButton />

				<Ricerca />
				<AccordionComp
					className="max-w-6xl px-4 py-4 md:py-8"
					defaultOpen={0}
					texts={t.annunci.accordion_minifaq}
				/>
			</main>
		</RicercaProvider>
	);
};
const GoBackButton = () => {
	const { page, setPage } = useRicerca();
	if (page >= 2) {
		return (
			<Button
				className="absolute right-0 h-auto py-0 text-base text-neutral-600 underline underline-offset-1 sm:hidden"
				onClick={async () => {
					await setPage(0);
				}}
				variant="link"
			>
				Torna all'inizio
			</Button>
		);
	}
};
export default Annunci;

Annunci.getLayout = (page: React.ReactNode) => {
	return (
		<Layout
			containerClassName="bg-background2"
			footerClassName="bg-background2"
		>
			{page}
		</Layout>
	);
};

export const getServerSideProps = (async () => {
	const helper = generateSSGHelper();
	const options = await helper.annunci.getAnnunciOptions.fetch();
	return {
		props: {
			options,
		},
	};
}) satisfies GetServerSideProps<AnnunciPageProps>;

const Ricerca = () => {
	const { map, page } = useRicerca();
	useEffect(() => {
		window.scrollTo({ behavior: "smooth", top: 0 });
	}, [page]);

	return (
		<div className="space-y-5">
			<RicercaFilters />

			{map ? <MapSection /> : <AnnunciList />}
		</div>
	);
};

const RicercaFilters = () => {
	const { t } = useTranslation();
	const {
		map,
		setMap,
		tipo,
		setTipo,
		comune,
		setComune,
		consegna,
		setConsegna,
		sort,
		setSort,
		comuniOptions,
		tipologieOptions,
		consegnaOptions,
		ResetParams,
		nFiltri,
	} = useRicerca();
	const [open, setOpen] = useState(false);

	const mappedConsegnaOptions = useMemo(
		// biome-ignore lint/style/noNonNullAssertion: <known lenght>
		() => consegnaOptions.map((m) => t.preferenze.mesi[m]!).filter(Boolean),
		[consegnaOptions, t.preferenze.mesi],
	);

	return (
		<div className="mx-auto w-full max-w-7xl space-y-5">
			<div className="flex w-full flex-col-reverse gap-4 sm:flex-row sm:gap-2">
				<div className="flex w-full gap-2 sm:w-auto">
					<div className="flex w-full sm:w-auto">
						<DropdownMenu onOpenChange={setOpen} open={open}>
							<DropdownMenuTrigger asChild>
								<Button
									className="group flex w-full flex-row gap-2 sm:w-auto"
									variant="default"
								>
									<Badge className="w-fit rounded-md bg-secondary px-1.5 py-0.5 text-secondary-foreground dark:group-hover:bg-transparent">
										{nFiltri}
									</Badge>
									<Filter className="size-5" />{" "}
									{nFiltri === 1
										? t.annunci.filtro_attivo
										: t.annunci.filtri_attivi}
									{open ? <ChevronUp /> : <ChevronDown />}
								</Button>
							</DropdownMenuTrigger>
							<DropdownMenuContent
								align="start"
								className="flex w-60 max-w-3xl flex-col gap-2 p-4"
							>
								<SelectFilter
									defaultValue={tipo}
									handleReset={async () => {
										await setTipo("");
									}}
									label={t.annunci.fs_tipologia.titolo}
									onValueChange={async (value: string) => {
										await setTipo(value);
									}}
									options={tipologieOptions}
									placeholder={t.seleziona_placeholder}
									value={tipo}
								/>
								<SelectFilter
									defaultValue={comune}
									handleReset={async () => {
										await setComune(null);
									}}
									label={t.annunci.comune}
									onValueChange={async (value: string) => {
										await setComune(value);
									}}
									options={comuniOptions}
									placeholder={t.seleziona_placeholder}
									value={comune}
								/>
								<SelectFilter
									defaultValue={
										consegna ? t.preferenze.mesi[consegna] || "" : ""
									}
									handleReset={async () => {
										await setConsegna(null);
									}}
									label={t.annunci.consegna}
									onValueChange={async (value: string) => {
										if (value === "") {
											await setConsegna(null);
											return;
										}
										if (t.preferenze.mesi.includes(value)) {
											await setConsegna(t.preferenze.mesi.indexOf(value));
											return;
										}
										console.warn("Value not found in preferenze.mesi");
										await setConsegna(null);
									}}
									options={mappedConsegnaOptions}
									placeholder={t.seleziona_placeholder}
									value={consegna ? t.preferenze.mesi[consegna] || "" : ""}
								/>
								<SelectFilter
									defaultValue={sort}
									handleReset={async () => {
										await setSort("");
									}}
									label={t.ordina_per}
									onValueChange={async (value: SortTypes) => {
										await setSort(value);
									}}
									options={["Recenti", "Prezzo", "Consegna", "Mq"]}
									placeholder={t.seleziona_placeholder}
									value={sort}
								/>
								<Button
									className="flex flex-row gap-2"
									disabled={nFiltri === 0}
									onClick={ResetParams}
									variant="destructive"
								>
									<FilterX className="size-5" /> {t.annunci.filtri_reset}
								</Button>
							</DropdownMenuContent>
						</DropdownMenu>
					</div>
					<Button
						className="flex w-fit flex-row gap-2"
						onClick={async () => {
							await setMap((v) => !v);
						}}
						variant="default"
					>
						{!map ? (
							<>
								<MapIcon className="size-5" />{" "}
								<span className="hidden sm:block">Mappa</span>
							</>
						) : (
							<>
								<Table className="size-5" />
								<span className="hidden sm:block">Lista</span>
							</>
						)}
					</Button>
				</div>
				<div className="flex w-full items-center justify-between gap-2 sm:justify-between">
					<div className="relative z-35 flex w-full gap-1 sm:w-auto">
						<CodiceBox
							className="h-10 w-full"
							inputId="annunci-search"
							optionBoxClassName="top-11 "
						/>
					</div>

					<CTA_TipologiaModal />
				</div>
			</div>
		</div>
	);
};

const AnnunciList = () => {
	const {
		tipo,
		comune,
		consegna,
		sort,
		map,
		page,
		setPage,
		isLoading: ricercaLoading,
	} = useRicerca();

	const { data, status, isPlaceholderData } =
		api.annunci.getWithCursor.useQuery(
			{
				comune: comune || undefined,
				consegna: consegna || undefined,
				page,
				pageSize: 6,
				sort: sort || undefined,
				tipologia: tipo || undefined,
			},
			{
				enabled: !map,
				placeholderData: keepPreviousData,
				staleTime: 5000,
			},
		);
	const utils = api.useUtils();
	useEffect(() => {
		const prefetchData = async () => {
			if (!isPlaceholderData && data?.hasMore) {
				await utils.annunci.getWithCursor.prefetch({
					comune: comune || undefined,
					consegna: consegna || undefined,
					page: page + 1,
					pageSize: 6,
					sort: sort || undefined,
					tipologia: tipo || undefined,
				});
			}
		};
		prefetchData().catch((err) => {
			console.error("Error prefetching next page:", err);
		});
	}, [data, isPlaceholderData, page]);

	useEffect(() => {
		// Reset to page 0 if current page has no data or less than page size
		const checkPage = async () => {
			if (data) {
				if (data.annunci.length === 0 && page !== 0) {
					await setPage(0);
				}
				if (data.annunci.length < 6 || !data.hasMore) {
					await setPage(0);
				}
			}
		};
		checkPage().catch((err) => {
			console.error("Error checking data for page reset:", err);
		});
	}, [data, tipo, comune, consegna, sort, setPage]);

	if (ricercaLoading) return <LoadingPage />;
	if (status === "error") return <Status500 />;

	return (
		<>
			{status === "pending" ? (
				<LoadingPage />
			) : (
				<AnnunciGrid pagedata={data.annunci} />
			)}

			<div className="flex items-center justify-center gap-2">
				<div className="flex w-24 items-center justify-end gap-2">
					{page >= 2 && (
						<Button
							aria-label="Go to first page"
							onClick={async () => {
								await setPage(0);
							}}
							title="Go to first page"
							variant="outline"
						>
							<ChevronsLeft className="h-4 w-4" />
						</Button>
					)}

					<Button
						aria-label="Previous page"
						disabled={page === 0}
						onClick={async () => {
							await setPage((old) => (old ? Math.max(old - 1, 0) : 0));
						}}
						title="Previous page"
						variant="outline"
					>
						<ChevronLeft className="h-4 w-4" />
					</Button>
				</div>

				<div className="mx-4 w-12 rounded-md bg-white py-2 text-center font-medium text-lg">
					{page + 1}
				</div>

				<div className="flex w-24 items-center justify-start gap-2">
					<Button
						aria-label="Next page"
						disabled={isPlaceholderData || !data?.hasMore}
						onClick={async () => {
							await setPage((old) =>
								old ? (data?.hasMore ? old + 1 : old) : 1,
							);
						}}
						title="Next page"
						variant="outline"
					>
						<ChevronRight className="h-4 w-4" />
					</Button>
				</div>
			</div>
		</>
	);
};

interface SelectFilterProps<T> {
	label: string;
	options: string[];
	defaultValue?: T;
	value: T | undefined;
	onValueChange: (value: T) => void;
	handleReset: () => void;
	placeholder: string;
}

export const SelectFilter = <T extends string>({
	label,
	options,
	defaultValue,
	value,
	onValueChange,
	placeholder,
	handleReset,
}: SelectFilterProps<T>) => {
	return (
		<div className="flex flex-col gap-2">
			<div className="flex h-4 flex-row gap-4 px-1">
				<Label
					className={cn(
						"font-semibold text-muted-foreground",
						value !== "" && "text-primary",
					)}
				>
					{label}
				</Label>
				{value !== "" && (
					<button onClick={handleReset} type="button">
						<RotateCcwIcon className="size-4" />
					</button>
				)}
			</div>

			<Select
				defaultValue={defaultValue}
				onValueChange={onValueChange}
				value={value}
			>
				<SelectTrigger className="w-full">
					<SelectValue placeholder={placeholder} />
				</SelectTrigger>
				<SelectContent>
					{options.map((option) => (
						<SelectItem className="text-left" key={option} value={option}>
							{option}
						</SelectItem>
					))}
				</SelectContent>
			</Select>
		</div>
	);
};
