"use client";
import {
	parseAsBoolean,
	parseAsInteger,
	parseAsString,
	parseAsStringLiteral,
	useQueryState,
} from "nuqs";
import {
	createContext,
	type FC,
	type ReactNode,
	useContext,
	useMemo,
	useTransition,
} from "react";

type RicercaContextType = {
	map: boolean;
	setMap: (
		value: boolean | ((old: boolean) => boolean | null) | null,
	) => Promise<URLSearchParams>;
	tipo: string;
	setTipo: (
		value: string | ((old: string) => string | null) | null,
	) => Promise<URLSearchParams>;
	comune: string;
	setComune: (
		value: string | ((old: string) => string | null) | null,
	) => Promise<URLSearchParams>;
	consegna: number | null;
	setConsegna: (
		value: number | ((old: number | null) => number | null) | null,
	) => Promise<URLSearchParams>;
	sort: SortTypes;
	setSort: (
		value: SortTypes | ((old: SortTypes) => SortTypes | null) | null,
	) => Promise<URLSearchParams>;

	comuniOptions: string[];
	tipologieOptions: string[];
	consegnaOptions: number[];
	sortOptions: typeof sortOptions;
	page: number;
	setPage: (
		value: number | ((old: number | null) => number | null) | null,
	) => Promise<URLSearchParams>;
	ResetParams: () => Promise<void>;
	nFiltri: number;
	isLoading: boolean;
};

const sortOptions = ["Recenti", "Prezzo", "Consegna", "Mq", ""] as const;

//sort as string union
export type SortTypes = (typeof sortOptions)[number];

export type AnnunciOptions = {
	comune: string;
	tipo: string;
	consegna: number;
}[];

const RicercaContext = createContext<RicercaContextType | undefined>(undefined);

export const useRicerca = () => {
	const context = useContext(RicercaContext);
	if (!context) {
		throw new Error("useRicerca must be used within a RicercaProvider");
	}
	return context;
};

export const RicercaProvider: FC<{
	children: ReactNode;
	options: AnnunciOptions;
}> = ({ children, options }) => {
	const [isLoading, startTransition] = useTransition();

	const [map, setMap] = useQueryState(
		"map",
		parseAsBoolean.withDefault(false).withOptions({ startTransition }),
	);
	const [tipo, setTipo] = useQueryState(
		"tipo",
		parseAsString.withDefault("").withOptions({ startTransition }),
	);
	const [comune, setComune] = useQueryState(
		"comune",
		parseAsString.withDefault("").withOptions({ startTransition }),
	);
	const [consegna, setConsegna] = useQueryState(
		"consegna",
		parseAsInteger.withOptions({ startTransition }),
	);
	const [sort, setSort] = useQueryState(
		"sort",
		parseAsStringLiteral(sortOptions)
			.withDefault("")
			.withOptions({ startTransition }),
	);

	const [page, setPage] = useQueryState(
		"p",
		parseAsInteger.withDefault(0).withOptions({ clearOnDefault: true }),
	);

	const tipologieOptions = useMemo(() => {
		const set = new Set<string>();
		options.forEach((item) => {
			if (!comune || item.comune === comune) {
				if (!consegna || item.consegna === consegna) {
					set.add(item.tipo);
				}
			}
		});
		return Array.from(set);
	}, [options, comune, consegna]);

	const comuniOptions = useMemo(() => {
		const set = new Set<string>();
		options.forEach((item) => {
			if (!tipo || item.tipo === tipo) {
				if (!consegna || item.consegna === consegna) {
					set.add(item.comune);
				}
			}
		});
		return Array.from(set);
	}, [options, tipo, consegna]);

	const consegnaOptions = useMemo(() => {
		const set = new Set<number>();
		options.forEach((item) => {
			if (!tipo || item.tipo === tipo) {
				if (!comune || item.comune === comune) {
					set.add(item.consegna);
				}
			}
		});
		return Array.from(set);
	}, [options, tipo, comune]);

	const ResetParams = async () => {
		await setTipo("");
		await setComune("");
		await setConsegna(null);
		await setSort("");
		await setPage(0);
	};

	const nFiltri =
		[tipo, comune, sort].reduce(
			(count, item) => (item !== "" ? count + 1 : count),
			0,
		) + (consegna !== null ? 1 : 0);

	return (
		<RicercaContext.Provider
			value={{
				comune,
				comuniOptions,
				consegna,
				consegnaOptions,
				isLoading,
				map,
				nFiltri,
				page,

				ResetParams,
				setComune,
				setConsegna,
				setMap,
				setPage,
				setSort,
				setTipo,
				sort,
				sortOptions: sortOptions,
				tipo,
				tipologieOptions,
			}}
		>
			{children}
		</RicercaContext.Provider>
	);
};
