"use client";

import * as React from "react";
import { createPortal } from "react-dom";
import { cn } from "@/lib/utils";

export type ToastVariant = "success" | "info" | "warning" | "destructive";

export type Toast = {
  id: string;
  title: React.ReactNode;
  description?: React.ReactNode;
  action?: React.ReactNode;
  variant?: ToastVariant;
  duration?: number; // ms, default 5000
};

type ToastContextValue = {
  toast: (t: Omit<Toast, "id">) => string;
  dismiss: (id: string) => void;
};

const ToastCtx = React.createContext<ToastContextValue | null>(null);

export function useToast() {
  const ctx = React.useContext(ToastCtx);
  if (!ctx)
    throw new Error("useToast must be called inside <ToastProvider> (added in RootLayout)");
  return ctx;
}

const VARIANT_STYLES: Record<ToastVariant, string> = {
  success:
    "bg-emerald-500/10 ring-1 ring-emerald-500/30 text-emerald-700 dark:text-emerald-300",
  info:
    "bg-violet-500/10 ring-1 ring-violet-500/30 text-violet-700 dark:text-violet-300",
  warning:
    "bg-amber-500/10 ring-1 ring-amber-500/30 text-amber-700 dark:text-amber-300",
  destructive:
    "bg-destructive/10 ring-1 ring-destructive/30 text-destructive dark:text-destructive",
};

const VARIANT_ICONS: Record<ToastVariant, string> = {
  success: "✓",
  info: "ℹ",
  warning: "⚠",
  destructive: "✕",
};

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

  React.useEffect(() => {
    // Defer the mounted flag to a separate task so React doesn't see a
    // synchronous setState during the effect body (lint rule).
    const id = setTimeout(() => setMounted(true), 0);
    return () => clearTimeout(id);
  }, []);

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

  const toast = React.useCallback(
    (t: Omit<Toast, "id">) => {
      const id =
        typeof crypto !== "undefined" && "randomUUID" in crypto
          ? crypto.randomUUID()
          : `toast-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
      const full: Toast = { id, variant: "success", duration: 5000, ...t };
      setToasts((prev) => [...prev, full]);
      if (full.duration && full.duration > 0) {
        setTimeout(() => dismiss(id), full.duration);
      }
      return id;
    },
    [dismiss],
  );

  const value = React.useMemo(() => ({ toast, dismiss }), [toast, dismiss]);

  return (
    <ToastCtx.Provider value={value}>
      {children}
      {mounted &&
        createPortal(
          <div
            aria-live="polite"
            className="pointer-events-none fixed inset-x-0 top-4 z-50 flex flex-col items-center gap-2 px-4"
          >
            {toasts.map((t) => {
              const variant = t.variant ?? "success";
              return (
                <div
                  key={t.id}
                  role="status"
                  className={cn(
                    "pointer-events-auto flex w-full max-w-md items-center gap-3 rounded-lg px-4 py-3 shadow-md backdrop-blur",
                    VARIANT_STYLES[variant],
                  )}
                >
                  <span className="text-base leading-none" aria-hidden="true">
                    {VARIANT_ICONS[variant]}
                  </span>
                  <div className="min-w-0 flex-1 text-sm">
                    <div className="font-medium text-foreground">{t.title}</div>
                    {t.description && (
                      <div className="text-xs text-muted-foreground mt-0.5">
                        {t.description}
                      </div>
                    )}
                  </div>
                  {t.action && <div className="shrink-0">{t.action}</div>}
                  <button
                    type="button"
                    onClick={() => dismiss(t.id)}
                    aria-label="Dismiss"
                    className="ml-1 shrink-0 text-muted-foreground hover:text-foreground"
                  >
                    ✕
                  </button>
                </div>
              );
            })}
          </div>,
          document.body,
        )}
    </ToastCtx.Provider>
  );
}
