"use client";

import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from "react";
import { CheckCircle2, Info, TriangleAlert, X, XCircle } from "lucide-react";
import clsx from "clsx";

/** Lightweight toast system for save confirmations and errors (SPEC 48). */

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

interface Toast {
  id: number;
  tone: ToastTone;
  title: string;
  description?: string;
}

interface ToastContextValue {
  toast: (input: { tone?: ToastTone; title: string; description?: string }) => void;
}

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

export function useToast(): ToastContextValue {
  const context = useContext(ToastContext);
  if (!context) {
    // A no-op keeps components usable in isolation (e.g. in tests).
    return { toast: () => undefined };
  }
  return context;
}

let nextId = 1;

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

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

  const toast = useCallback<ToastContextValue["toast"]>((input) => {
    const item: Toast = {
      id: nextId++,
      tone: input.tone ?? "success",
      title: input.title,
      description: input.description,
    };
    setToasts((current) => [...current.slice(-3), item]);
  }, []);

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

  return (
    <ToastContext.Provider value={value}>
      {children}
      <div
        aria-live="polite"
        aria-atomic="false"
        className="pointer-events-none fixed bottom-4 right-4 z-50 flex w-[min(24rem,calc(100vw-2rem))] flex-col gap-2"
      >
        {toasts.map((item) => (
          <ToastCard key={item.id} toast={item} onDismiss={() => dismiss(item.id)} />
        ))}
      </div>
    </ToastContext.Provider>
  );
}

function ToastCard({ toast, onDismiss }: { toast: Toast; onDismiss: () => void }) {
  useEffect(() => {
    const timer = setTimeout(onDismiss, toast.tone === "error" ? 9000 : 4500);
    return () => clearTimeout(timer);
  }, [onDismiss, toast.tone]);

  const tones = {
    success: { ring: "ring-teal-100", bg: "bg-white", icon: <CheckCircle2 className="h-4 w-4 text-teal-600" /> },
    error: { ring: "ring-rose-100", bg: "bg-white", icon: <XCircle className="h-4 w-4 text-rose-600" /> },
    warning: { ring: "ring-amber-100", bg: "bg-white", icon: <TriangleAlert className="h-4 w-4 text-amber-600" /> },
    info: { ring: "ring-brand-100", bg: "bg-white", icon: <Info className="h-4 w-4 text-brand-600" /> },
  } as const;
  const tone = tones[toast.tone];

  return (
    <div
      className={clsx(
        "animate-fade-up pointer-events-auto flex items-start gap-3 rounded-lg px-4 py-3 shadow-lg ring-1",
        tone.bg,
        tone.ring,
      )}
      role={toast.tone === "error" ? "alert" : "status"}
    >
      <span className="mt-0.5 shrink-0">{tone.icon}</span>
      <div className="min-w-0 flex-1">
        <p className="text-[13px] font-semibold text-ink-900">{toast.title}</p>
        {toast.description ? <p className="mt-0.5 text-[12px] leading-snug text-ink-600">{toast.description}</p> : null}
      </div>
      <button
        type="button"
        onClick={onDismiss}
        className="shrink-0 rounded p-0.5 text-ink-400 hover:bg-ink-100 hover:text-ink-600"
        aria-label="Dismiss notification"
      >
        <X className="h-3.5 w-3.5" />
      </button>
    </div>
  );
}
