import { type ClassValue, clsx } from "clsx";
import {
	useGlobalSearchParams,
	useLocalSearchParams,
	useRouter,
} from "expo-router";
import { useCallback, useReducer } from "react";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
	return twMerge(clsx(inputs));
}

export const useForceRerender = () => {
	return useReducer((x) => x + 1, 0)[1];
};

export function setServerData(_key: string, _val: any) {}
export function getServerData(key: string): any {
	return key;
}

export const useQueryState = <S>(key: string, initial: S) => {
	const params = useLocalSearchParams();
	const global = useGlobalSearchParams();
	const router = useRouter();

	const state = (params[key] as S) ?? (global[key] as S) ?? initial;
	const update = useCallback(
		(val: S | ((old: S) => S)) => {
			router.setParams({ [key]: val } as any);
		},
		[router, key],
	);
	return [state, update] as const;
};

export const getDisplayDate = ({
	startAir,
	endAir,
	airDate,
}: {
	startAir?: Date | null;
	endAir?: Date | null;
	airDate?: Date | null;
}) => {
	if (startAir) {
		if (!endAir || startAir.getFullYear() === endAir.getFullYear()) {
			return startAir.getFullYear().toString();
		}
		return (
			startAir.getFullYear() + (endAir ? ` - ${endAir.getFullYear()}` : "")
		);
	}
	if (airDate) {
		return airDate.getFullYear().toString();
	}
	return null;
};

export const displayRuntime = (runtime: number | null) => {
	if (!runtime) return null;
	if (runtime < 60) return `${runtime}min`;
	return `${Math.floor(runtime / 60)}h${runtime % 60}`;
};

// shuffle an array in place, stolen from https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
export function shuffle<T>(array: T[]): T[] {
	let currentIndex = array.length;

	while (currentIndex !== 0) {
		const randomIndex = Math.floor(Math.random() * currentIndex);
		currentIndex--;

		[array[currentIndex], array[randomIndex]] = [
			array[randomIndex],
			array[currentIndex],
		];
	}

	return array;
}

export function uniq<T>(a: T[]): T[] {
	return uniqBy(a, (x) => x as string);
}

export function uniqBy<T>(a: T[], key: (val: T) => string | number): T[] {
	const seen: Record<string, boolean> = {};
	return a.filter((item) => {
		const k = key(item);
		if (seen[k]) return false;
		seen[k] = true;
		return true;
	});
}
