"use client";

import { createContext, useCallback, useContext, useRef, useState } from "react";
import { Spinner } from "@/components/ui/spinner";
import { FOCUS_RING_CLASSES } from "@/components/ui/styles";
import { cn } from "@/lib/utils";

export type ToastVariant = "success" | "error" | "loading" | "info";

interface ToastItem {
  id: number;
  message: string;
  variant: ToastVariant;
}

interface ToastContextValue {
  /** Shows a toast and returns its id. "loading" toasts never auto-dismiss. */
  toast: (message: string, variant?: ToastVariant) => number;
  /** Turns a "loading" toast into success/error (e.g. after an async action settles). */
  update: (id: number, message: string, variant: ToastVariant) => void;
  dismiss: (id: number) => void;
}

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

export function useToast() {
  const ctx = useContext(ToastContext);
  if (!ctx) throw new Error("useToast must be used within ToastProvider");
  return ctx;
}

const AUTO_DISMISS_MS = 4000;

const VARIANT_CLASSES: Record<ToastVariant, string> = {
  success: "border-green-200 bg-green-50 text-green-800",
  error: "border-red-200 bg-red-50 text-red-700",
  loading: "border-kolabora-neutral-dark/10 bg-kolabora-neutral-white text-kolabora-neutral-dark",
  info: "border-kolabora-neutral-dark/10 bg-kolabora-neutral-white text-kolabora-neutral-dark",
};

export function ToastProvider({ children }: { children: React.ReactNode }) {
  const [items, setItems] = useState<ToastItem[]>([]);
  const nextId = useRef(0);
  const timers = useRef<Map<number, ReturnType<typeof setTimeout>>>(new Map());

  const dismiss = useCallback((id: number) => {
    setItems((prev) => prev.filter((item) => item.id !== id));
    const timer = timers.current.get(id);
    if (timer) {
      clearTimeout(timer);
      timers.current.delete(id);
    }
  }, []);

  const scheduleAutoDismiss = useCallback(
    (id: number) => {
      const existing = timers.current.get(id);
      if (existing) clearTimeout(existing);
      timers.current.set(
        id,
        setTimeout(() => dismiss(id), AUTO_DISMISS_MS),
      );
    },
    [dismiss],
  );

  const toast = useCallback(
    (message: string, variant: ToastVariant = "info") => {
      const id = nextId.current++;
      setItems((prev) => [...prev, { id, message, variant }]);
      if (variant !== "loading") scheduleAutoDismiss(id);
      return id;
    },
    [scheduleAutoDismiss],
  );

  const update = useCallback(
    (id: number, message: string, variant: ToastVariant) => {
      setItems((prev) => prev.map((item) => (item.id === id ? { ...item, message, variant } : item)));
      if (variant !== "loading") scheduleAutoDismiss(id);
    },
    [scheduleAutoDismiss],
  );

  return (
    <ToastContext.Provider value={{ toast, update, dismiss }}>
      {children}
      <div
        aria-live="polite"
        aria-atomic="false"
        className="pointer-events-none fixed inset-x-4 bottom-4 z-50 flex flex-col items-center gap-2 sm:inset-x-auto sm:right-6 sm:bottom-6 sm:items-end"
      >
        {items.map((item) => (
          <div
            key={item.id}
            role="status"
            className={cn(
              "toast-enter pointer-events-auto flex w-full max-w-sm items-center gap-2 rounded-xl border px-4 py-3 text-sm font-medium shadow-lg",
              VARIANT_CLASSES[item.variant],
            )}
          >
            {item.variant === "loading" && <Spinner className="h-4 w-4 shrink-0" />}
            <span className="min-w-0 flex-1">{item.message}</span>
            <button
              type="button"
              onClick={() => dismiss(item.id)}
              aria-label="Close notification"
              className={cn("shrink-0 rounded text-current/60 hover:text-current", FOCUS_RING_CLASSES)}
            >
              &times;
            </button>
          </div>
        ))}
      </div>
    </ToastContext.Provider>
  );
}
