import React, { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react';
import { CheckCircle2, AlertCircle, Info, X } from 'lucide-react';

type ToastType = 'success' | 'error' | 'info';
interface ToastItem {
  id: number;
  message: string;
  type: ToastType;
}

interface ToastApi {
  success: (message: string) => void;
  error: (message: string) => void;
  info: (message: string) => void;
}

const ToastContext = createContext<ToastApi | null>(null);

const AUTO_DISMISS_MS = 4000;

const TYPE_STYLE: Record<ToastType, { wrap: string; icon: string; Icon: typeof CheckCircle2; role: 'status' | 'alert' }> = {
  success: {
    wrap: 'border-emerald-200 bg-emerald-50 text-emerald-900 dark:bg-emerald-950/60 dark:border-emerald-800/60 dark:text-emerald-100',
    icon: 'text-emerald-600 dark:text-emerald-400',
    Icon: CheckCircle2,
    role: 'status',
  },
  error: {
    wrap: 'border-rose-200 bg-rose-50 text-rose-900 dark:bg-rose-950/60 dark:border-rose-800/60 dark:text-rose-100',
    icon: 'text-rose-600 dark:text-rose-400',
    Icon: AlertCircle,
    role: 'alert',
  },
  info: {
    wrap: 'border-blue-200 bg-blue-50 text-blue-900 dark:bg-blue-950/60 dark:border-blue-800/60 dark:text-blue-100',
    icon: 'text-blue-600 dark:text-blue-400',
    Icon: Info,
    role: 'status',
  },
};

export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [toasts, setToasts] = useState<ToastItem[]>([]);
  // Monotonic counter — avoids Date.now() collisions when two toasts fire in
  // the same millisecond, and survives clock changes / NTP corrections.
  const idRef = useRef(0);
  const timersRef = useRef<Map<number, ReturnType<typeof setTimeout>>>(new Map());

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

  const addToast = useCallback((message: string, type: ToastType) => {
    const id = ++idRef.current;
    setToasts((prev) => [...prev, { id, message, type }]);
    const timer = setTimeout(() => removeToast(id), AUTO_DISMISS_MS);
    timersRef.current.set(id, timer);
  }, [removeToast]);

  // Clear any pending timers when the provider unmounts (e.g. HMR / test
  // teardown) so we don't call setState on a dead component.
  useEffect(() => {
    const timers = timersRef.current;
    return () => {
      timers.forEach(clearTimeout);
      timers.clear();
    };
  }, []);

  const api = useRef<ToastApi>({
    success: (m: string) => addToast(m, 'success'),
    error: (m: string) => addToast(m, 'error'),
    info: (m: string) => addToast(m, 'info'),
  }).current;

  return (
    <ToastContext.Provider value={api}>
      {children}
      <div
        aria-live="polite"
        aria-atomic="false"
        className="fixed top-4 right-4 z-[9999] flex flex-col gap-2 pointer-events-none max-w-[calc(100vw-2rem)]"
      >
        {toasts.map((t) => {
          const style = TYPE_STYLE[t.type];
          return (
            <div
              key={t.id}
              role={style.role}
              className={`pointer-events-auto flex items-start gap-3 min-w-[260px] max-w-sm border rounded-2xl px-4 py-3 shadow-lg shadow-black/5 backdrop-blur-sm animate-in slide-in-from-right-4 fade-in duration-200 ${style.wrap}`}
            >
              <style.Icon size={18} className={`shrink-0 mt-0.5 ${style.icon}`} aria-hidden="true" />
              <p className="text-sm font-medium leading-snug flex-1 break-words">{t.message}</p>
              <button
                type="button"
                onClick={() => removeToast(t.id)}
                aria-label="Dismiss notification"
                className="shrink-0 opacity-60 hover:opacity-100 transition-opacity rounded-md p-0.5 -mr-1"
              >
                <X size={14} aria-hidden="true" />
              </button>
            </div>
          );
        })}
      </div>
    </ToastContext.Provider>
  );
};

export const useToast = (): ToastApi => {
  const context = useContext(ToastContext);
  if (!context) throw new Error('useToast must be used within ToastProvider');
  return context;
};
