import { keepPreviousData } from "@tanstack/react-query";
import {
	ChevronDown,
	ChevronUp,
	Filter,
	FilterX,
	MapIcon,
	RotateCcwIcon,
	Table,
} from "lucide-react";
import type { GetServerSideProps } from "next";
import dynamic from "next/dynamic";
import Head from "next/head";
import { useCallback, useEffect, useMemo, useState } from "react";
import { AccordionComp } from "~/components/accordionComp";
import { CTA_TipologiaModal } from "~/components/annunci_tutorial";
import { LazyCardAnnuncio } from "~/components/annuncio_card";
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";

const MapSection = dynamic(
	() =>
		import("~/components/annunci_map").then((mod) => ({
			default: mod.MapSection,
		})),
	{
		ssr: false,
		loading: () => <LoadingPage />,
	},
);

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-10xl space-y-5 bg-background px-2 py-5 md:px-8">
				<Badge className="bg-muted py-1 text-foreground text-sm outline outline-muted-foreground">
					{t.annunci.titolo}
				</Badge>

				<Ricerca />
				<AccordionComp
					className="max-w-6xl px-4 py-4 md:py-8"
					defaultOpen={0}
					texts={t.annunci.accordion_minifaq}
				/>
			</main>
		</RicercaProvider>
	);
};

export default Annunci;

Annunci.getLayout = (page: React.ReactNode) => {
	return <Layout>{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 } = useRicerca();

	return (
		<div className="mx-auto w-full space-y-5">
			<RicercaHeader />
			<div className="relative flex w-full gap-4">
				<RicercaSideFilters />
				<div className="flex-1">{map ? <MapSection /> : <AnnunciList />}</div>
			</div>
		</div>
	);
};

const Filters = () => {
	const { t } = useTranslation();
	const {
		tipo,
		setTipo,
		comune,
		setComune,
		consegna,
		setConsegna,
		sort,
		setSort,
		comuniOptions,
		tipologieOptions,
		consegnaOptions,
		ResetParams,
		nFiltri,
	} = useRicerca();
	const mappedConsegnaOptions = useMemo(
		// biome-ignore lint/style/noNonNullAssertion: <known lenght>
		() => consegnaOptions.map((m) => t.preferenze.mesi[m]!).filter(Boolean),
		[consegnaOptions, t.preferenze.mesi],
	);
	return (
		<>
			<SelectFilter
				defaultValue={""}
				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={""}
				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={""}
				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("Recenti");
				}}
				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>
		</>
	);
};

const RicercaSideFilters = () => {
	return (
		<div className="hidden h-fit w-46 max-w-46 shrink-0 grow-0 flex-col gap-3 overflow-clip rounded-md bg-secondary p-2 outline-neutral-300 2xl:flex">
			<Filters />
		</div>
	);
};

const DrowdownFilters = () => {
	const { t } = useTranslation();
	const { nFiltri } = useRicerca();
	const [open, setOpen] = useState(false);

	// Close dropdown when page resizes
	const handleResize = useCallback(() => {
		setOpen(false);
	}, []);

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

	return (
		<div className="flex w-full sm:w-auto 2xl:hidden">
			<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"
				>
					<Filters />
				</DropdownMenuContent>
			</DropdownMenu>
		</div>
	);
};

const RicercaHeader = () => {
	const { map, setMap } = useRicerca();

	return (
		<div className="mx-auto w-full max-w-10xl space-y-5">
			<div className="flex w-full flex-col-reverse gap-2 sm:flex-row">
				<div className="flex w-full items-center gap-2 sm:w-auto">
					<DrowdownFilters />
					<Button
						className="flex w-fit flex-row items-center 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-9 w-full"
							inputId="annunci-search"
							optionBoxClassName="top-11 "
						/>
					</div>

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

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

	const { data, status } = api.annunci.annunciRicerca.useQuery(
		{
			comune: comune || undefined,
			consegna: consegna || undefined,
			sort: sort || undefined,
			tipologia: tipo || undefined,
		},
		{
			enabled: !map,
			placeholderData: keepPreviousData,
			staleTime: 5000,
		},
	);

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

	return (
		<div className="w-full space-y-4">
			{status === "pending" ? (
				<LoadingPage />
			) : (
				<div className="relative z-0 mx-auto grid w-full grid-flow-row grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4">
					{data.map((annuncio, idx) => (
						<LazyCardAnnuncio
							key={annuncio.codice}
							{...annuncio}
							eager={idx <= 9}
							videos={[]}
						/>
					))}
				</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 !== defaultValue && "text-primary",
					)}
				>
					{label}
				</Label>
				{value !== defaultValue && (
					<button
						className="cursor-pointer"
						onClick={handleReset}
						type="button"
					>
						<RotateCcwIcon className="size-4" />
					</button>
				)}
			</div>

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