import { DangerMessageBlock, SuccessMessageBlock, WarningMessageBlock } from "$/component/message";
import Toaster from "$/component/toaster/Toaster";
import type { Toast, ToastProviderProps, ToastProviderState } from "$/types/ToasterTypes";
import moment from "moment";
import { createContext, useCallback, useContext, useMemo, useState } from "react";


const toastInitialState: ToastProviderState = {
	toast: [],
	hideToast: () => {},
	addToast: () => "",
	addSuccess: () => "",
	addWarning: () => "",
	addDanger: () => ""
};

const ToasterProviderContext = createContext<ToastProviderState>(toastInitialState);


export default function ToasterProvider({
	className,
	children
}: ToastProviderProps){
	const [ toast, setToast ] = useState<Toast[]>([]);


	const hideToast = useCallback((id: string) => {
		setToast((prev) => {
			if(prev.length === 1 && prev[0].id === id){
				const current =  prev[0].hideTime > moment(new Date()).subtract(600, "ms").toDate() ? [...prev] : [];
				if(current.length > 0){
					setTimeout(() => hideToast(id), 600);
				}
				return current;
			}
			else{
				return prev.filter((toast) => toast.id !== id);
			}
		});
	}, []);

	const addToast = useCallback((message: React.ReactNode, duration?: number) => {
		if(!duration){
			duration = 5000;
		}
		const id = crypto.randomUUID();

		setToast((prev) => [ ...prev, { id, message, duration, hideTime: moment(new Date()).add(duration, "ms").toDate() } ]);
		setTimeout(() => hideToast(id), duration);

		return id;
	}, [hideToast]);

	const addSuccess = useCallback((message: React.ReactNode, duration?: number) => {
		return addToast(<SuccessMessageBlock>{message}</SuccessMessageBlock>, duration);
	}, [ addToast ]);

	const addWarning = useCallback((message: React.ReactNode, duration?: number) => {
		return addToast(<WarningMessageBlock>{message}</WarningMessageBlock>, duration);
	}, [ addToast ]);

	const addDanger = useCallback((message: React.ReactNode, duration?: number) => {
		return addToast(<DangerMessageBlock>{message}</DangerMessageBlock>, duration);
	}, [ addToast ]);

	const value: ToastProviderState = useMemo(() => ({
		toast,
		hideToast,
		addToast,
		addSuccess,
		addWarning,
		addDanger
	}), [ toast, hideToast, addToast, addSuccess, addWarning, addDanger ]);

	return (
		<ToasterProviderContext.Provider value={value}>
			<Toaster
				toast={toast}
				className={className}
			/>
			{children}
		</ToasterProviderContext.Provider>
	);
}


// eslint-disable-next-line react-refresh/only-export-components
export function useToaster(){
	const context = useContext(ToasterProviderContext);

	if(!context){
		throw new Error("useToaster must be used within a ToasterProvider");
	}

	return context;
}
