"use client";
import {
	parseAsArrayOf,
	parseAsBoolean,
	parseAsInteger,
	parseAsString,
	parseAsStringLiteral,
	useQueryStates,
} from "nuqs";
import {
	createContext,
	type FC,
	type ReactNode,
	useCallback,
	useContext,
	useEffect,
	useMemo,
	useState,
	useTransition,
} from "react";

const sortOptions = ["Recenti", "Prezzo", "Consegna", "Mq"] as const;
export type SortTypes = (typeof sortOptions)[number];

type RicercaUrlParams = {
	map: boolean;
	tipo: string;
	comune: string;
	consegna: number[];
	minBudget: number;
	maxBudget: number;
	sort: SortTypes;
};

export const paramsMapping = {
	map: "m",
	tipo: "t",
	comune: "c",
	consegna: "f",
	minBudget: "bmin",
	maxBudget: "bmax",
	sort: "s",
} as const;

export const buildRicercaUrl = (params: Partial<RicercaUrlParams>): string => {
	const searchParams = new URLSearchParams();
	Object.entries(params).forEach(([key, value]) => {
		const mappedKey = paramsMapping[key as keyof typeof paramsMapping];
		if (value !== undefined && value !== null) {
			searchParams.set(mappedKey, value.toString());
		}
	});
	const queryString = searchParams.toString();
	return queryString ? `/annunci?${queryString}` : "/annunci";
};

type RicercaContextType = {
	map: boolean;
	tipo: RicercaUrlParams["tipo"];
	comune: RicercaUrlParams["comune"] | null;
	consegna: RicercaUrlParams["consegna"] | null;
	minBudget: RicercaUrlParams["minBudget"] | null;
	maxBudget: RicercaUrlParams["maxBudget"] | null;
	sort: SortTypes;

	setAllParams: (
		params: Partial<{
			tipo: RicercaUrlParams["tipo"];
			comune: RicercaUrlParams["comune"] | null;
			consegna: RicercaUrlParams["consegna"] | null;
			minBudget: RicercaUrlParams["minBudget"] | null;
			maxBudget: RicercaUrlParams["maxBudget"] | null;
			sort: RicercaUrlParams["sort"];
			map: RicercaUrlParams["map"];
		}>,
	) => Promise<URLSearchParams>;
	reset: () => void;

	comuniOptions: string[];
	tipologieOptions: string[];
	consegnaOptions: number[];
	sortOptions: typeof sortOptions;
	nFiltri: number;
	isLoading: boolean;
};

export type AnnunciOptions = {
	comune: string;
	tipo: string;
	consegna: number;
	prezzo: 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 [nFiltri, setNFiltri] = useState(0);
	const [isLoading, startTransition] = useTransition();

	const [
		{ map, tipo, comune, consegna, minBudget, maxBudget, sort },
		setAllParams,
	] = useQueryStates(
		{
			map: parseAsBoolean.withDefault(false),
			tipo: parseAsString.withDefault(""),
			comune: parseAsString.withDefault(""),
			consegna: parseAsArrayOf(parseAsInteger),
			minBudget: parseAsInteger,
			maxBudget: parseAsInteger,
			sort: parseAsStringLiteral(sortOptions).withDefault("Recenti"),
		},
		{ startTransition, shallow: true, urlKeys: paramsMapping },
	);

	const reset = useCallback(() => {
		setAllParams({
			tipo: "",
			comune: "",
			consegna: null,
			minBudget: null,
			maxBudget: null,
			sort: "Recenti",
		});
	}, []);

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

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

	const consegnaOptions = useMemo(() => {
		const set = new Set<number>();
		options.forEach((item) => {
			if (!tipo || item.tipo === tipo) {
				if (!comune || item.comune === comune) {
					if (!minBudget || item.prezzo >= minBudget) {
						if (!maxBudget || item.prezzo <= maxBudget) {
							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, minBudget, maxBudget]);

	const updateNFiltri = () => {
		setNFiltri(
			[tipo, comune].reduce(
				(count, item) => (item !== "" ? count + 1 : count),
				0,
			) +
				(consegna !== null ? 1 : 0) +
				(sort !== "Recenti" ? 1 : 0) +
				(minBudget !== null ? 1 : 0) +
				(maxBudget !== null ? 1 : 0),
		);
	};

	useEffect(() => {
		updateNFiltri();
	}, [tipo, comune, consegna, minBudget, maxBudget, sort]);

	return (
		<RicercaContext.Provider
			value={{
				map,
				tipo,
				comune,
				consegna,
				minBudget,
				maxBudget,
				sort,

				setAllParams,
				reset,

				comuniOptions,
				consegnaOptions,
				tipologieOptions,
				sortOptions,
				nFiltri,
				isLoading,
			}}
		>
			{children}
		</RicercaContext.Provider>
	);
};
