"use client";

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

type ToastTone = "success" | "error" | "info";

type ToastItem = {
  id: string;
  tone: ToastTone;
  message: string;
};

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

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

const AUTO_DISMISS_MS = 4000;

export function useToast(): ToastApi {
  const ctx = useContext(ToastContext);
  if (!ctx) {
    // Safe no-op fallback so non-wrapped components don't crash.
    return {
      success: () => {},
      error: () => {},
      info: () => {},
    };
  }
  return ctx;
}

export function ToastProvider({ children }: { children: ReactNode }) {
  const [toasts, setToasts] = useState<ToastItem[]>([]);
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    // Gate portal render until after hydration to avoid SSR mismatch.
    // eslint-disable-next-line react-hooks/set-state-in-effect
    setMounted(true);
  }, []);

  const remove = useCallback((id: string) => {
    setToasts((prev) => prev.filter((t) => t.id !== id));
  }, []);

  const push = useCallback(
    (tone: ToastTone, message: string) => {
      const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
      setToasts((prev) => [...prev, { id, tone, message }]);
      setTimeout(() => {
        setToasts((prev) => prev.filter((t) => t.id !== id));
      }, AUTO_DISMISS_MS);
    },
    [],
  );

  const api = useMemo<ToastApi>(
    () => ({
      success: (message: string) => push("success", message),
      error: (message: string) => push("error", message),
      info: (message: string) => push("info", message),
    }),
    [push],
  );

  return (
    <ToastContext.Provider value={api}>
      {children}
      {mounted &&
        createPortal(
          <div
            aria-live="polite"
            className="pointer-events-none fixed bottom-4 right-4 z-[9999] flex max-w-[calc(100vw-2rem)] flex-col gap-3"
          >
            {toasts.map((t) => (
              <div
                key={t.id}
                role="status"
                className={[
                  "pointer-events-auto min-w-[18rem] max-w-md rounded-2xl border bg-white px-5 py-4 text-sm shadow-2xl",
                  "animate-[slide-up_0.2s_ease-out]",
                  t.tone === "success" ? "border-emerald-500/70" : "",
                  t.tone === "error" ? "border-rose-500/70" : "",
                  t.tone === "info" ? "border-border" : "",
                ].join(" ")}
                onClick={() => remove(t.id)}
              >
                <div className="flex items-start gap-3">
                  <span
                    className={[
                      "mt-1 inline-block h-2 w-2 shrink-0 rounded-full",
                      t.tone === "success" ? "bg-emerald-500" : "",
                      t.tone === "error" ? "bg-rose-500" : "",
                      t.tone === "info" ? "bg-slate-400" : "",
                    ].join(" ")}
                    aria-hidden="true"
                  />
                  <p className="leading-relaxed text-foreground">{t.message}</p>
                </div>
              </div>
            ))}
            <style>{`
              @keyframes slide-up {
                from { transform: translateY(10px); opacity: 0; }
                to { transform: translateY(0); opacity: 1; }
              }
            `}</style>
          </div>,
          document.body,
        )}
    </ToastContext.Provider>
  );
}
