"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;
	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("Recenti")
			.withOptions({ startTransition }),
	);

	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).sort((a, b) => a.localeCompare(b));
	}, [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);
				}
			}
		});
		const currentMonth = new Date().getMonth() + 1; // 1-12

		return Array.from(set).sort((a, b) => {
			// Calculate distance from current month (wrapping around)
			const distA = (a - currentMonth + 12) % 12;
			const distB = (b - currentMonth + 12) % 12;
			return distA - distB;
		});
	}, [options, tipo, comune]);

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

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

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

				ResetParams,
				setComune,
				setConsegna,
				setMap,

				setSort,
				setTipo,
				sort,
				sortOptions: sortOptions,
				tipo,
				tipologieOptions,
			}}
		>
			{children}
		</RicercaContext.Provider>
	);
};
