import React, {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';

export type ToastLevel = 'info' | 'success' | 'warn' | 'error';

export interface Toast {
  id: string;
  level: ToastLevel;
  message: string;
  detail?: string;
  createdAt: number;
  durationMs: number;
}

export interface ShowToastOptions {
  level?: ToastLevel;
  detail?: string;
  /** Override default auto-dismiss; 0 = stay until dismissed */
  durationMs?: number;
}

export const TOAST_DURATION_MS: Record<ToastLevel, number> = {
  info: 5000,
  success: 5000,
  warn: 6000,
  error: 10000,
};

export const MAX_VISIBLE_TOASTS = 5;

let toastCounter = 0;
function nextToastId(): string {
  toastCounter += 1;
  return `toast-${toastCounter}`;
}

export interface ToastContextValue {
  toasts: Toast[];
  showToast: (message: string, options?: ShowToastOptions) => string;
  dismissToast: (id: string) => void;
  clearAllToasts: () => void;
}

const ToastContext = createContext<ToastContextValue>({
  toasts: [],
  showToast: () => '',
  dismissToast: () => {},
  clearAllToasts: () => {},
});

export function ToastProvider({ children }: { children: React.ReactNode }) {
  const [toasts, setToasts] = useState<Toast[]>([]);
  const timersRef = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());

  const dismissToast = useCallback((id: string) => {
    const timer = timersRef.current.get(id);
    if (timer) {
      clearTimeout(timer);
      timersRef.current.delete(id);
    }
    setToasts((prev) => prev.filter((t) => t.id !== id));
  }, []);

  const clearAllToasts = useCallback(() => {
    for (const timer of timersRef.current.values()) clearTimeout(timer);
    timersRef.current.clear();
    setToasts([]);
  }, []);

  const scheduleDismiss = useCallback(
    (toast: Toast) => {
      if (toast.durationMs <= 0) return;
      const timer = setTimeout(() => dismissToast(toast.id), toast.durationMs);
      timersRef.current.set(toast.id, timer);
    },
    [dismissToast],
  );

  const showToast = useCallback(
    (message: string, options?: ShowToastOptions) => {
      const level = options?.level ?? 'info';
      const durationMs = options?.durationMs ?? TOAST_DURATION_MS[level];
      const toast: Toast = {
        id: nextToastId(),
        level,
        message,
        detail: options?.detail,
        createdAt: Date.now(),
        durationMs,
      };
      setToasts((prev) => [toast, ...prev].slice(0, MAX_VISIBLE_TOASTS));
      scheduleDismiss(toast);
      return toast.id;
    },
    [scheduleDismiss],
  );

  useEffect(() => {
    const timers = timersRef.current;
    return () => {
      for (const timer of timers.values()) clearTimeout(timer);
      timers.clear();
    };
  }, []);

  const value = useMemo(
    () => ({ toasts, showToast, dismissToast, clearAllToasts }),
    [toasts, showToast, dismissToast, clearAllToasts],
  );

  return <ToastContext.Provider value={value}>{children}</ToastContext.Provider>;
}

export function useToast(): ToastContextValue {
  return useContext(ToastContext);
}
