import {
  createContext,
  useContext,
  useState,
  useCallback,
  useMemo,
  useRef,
  useEffect,
  type ReactNode,
} from "react";

interface Alert {
  id: string;
  message: string;
  type: "success" | "error" | "warning" | "info";
}

interface AlertMethods {
  addAlert: (message: string, type?: string, duration?: number) => string;
  removeAlert: (id: string) => void;
  success: (message: string, duration?: number) => string;
  error: (message: string, duration?: number) => string;
  warning: (message: string, duration?: number) => string;
  info: (message: string, duration?: number) => string;
}

interface AlertStateValue {
  alerts: Alert[];
  removeAlert: (id: string) => void;
}

const AlertContext = createContext<AlertMethods | null>(null);
const AlertStateContext = createContext<AlertStateValue | null>(null);

export function AlertProvider({ children }: { children: ReactNode }) {
  const [alerts, setAlerts] = useState<Alert[]>([]);

  const removeAlert = useCallback((id: string) => {
    setAlerts((prev) => prev.filter((alert) => alert.id !== id));
  }, []);

  const counterRef = useRef(0);
  const timeoutsRef = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());

  useEffect(() => {
    return () => {
      timeoutsRef.current.forEach(clearTimeout);
      timeoutsRef.current.clear();
    };
  }, []);

  const addAlert = useCallback(
    (message: string, type = "success", duration = 4000) => {
      const id = `${Date.now()}-${counterRef.current++}`;
      setAlerts((prev) => [
        ...prev,
        { id, message, type: type as Alert["type"] },
      ]);
      if (duration > 0) {
        const timeoutId = setTimeout(() => {
          timeoutsRef.current.delete(timeoutId);
          removeAlert(id);
        }, duration);
        timeoutsRef.current.add(timeoutId);
      }
      return id;
    },
    [removeAlert],
  );

  const methods = useMemo<AlertMethods>(
    () => ({
      addAlert,
      removeAlert,
      success: (message, duration) => addAlert(message, "success", duration),
      error: (message, duration) => addAlert(message, "error", duration),
      warning: (message, duration) => addAlert(message, "warning", duration),
      info: (message, duration) => addAlert(message, "info", duration),
    }),
    [addAlert, removeAlert],
  );

  return (
    <AlertContext.Provider value={methods}>
      <AlertStateContext.Provider value={{ alerts, removeAlert }}>
        {children}
      </AlertStateContext.Provider>
    </AlertContext.Provider>
  );
}

export function useAlert(): AlertMethods {
  const context = useContext(AlertContext);
  if (!context)
    throw new Error("useAlert must be used within an AlertProvider");
  return context;
}

export function useAlertState(): AlertStateValue {
  const context = useContext(AlertStateContext);
  if (!context)
    throw new Error("useAlertState must be used within an AlertProvider");
  return context;
}
