"use client"

import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { XIcon, CheckCircle2Icon, AlertCircleIcon, AlertTriangleIcon, InfoIcon } from "lucide-react"
import { cn } from "../core/cn"

const toastVariants = cva(
  "group/toast pointer-events-auto relative flex w-full items-start gap-3 overflow-hidden rounded-xl border p-4 pr-8 shadow-lg transition-all",
  {
    variants: {
      variant: {
        default: "bg-background text-foreground border-border",
        success: "bg-background border-l-4 border-l-green-500 border-border text-foreground",
        error: "bg-background border-l-4 border-l-destructive border-border text-foreground",
        warning: "bg-background border-l-4 border-l-yellow-500 border-border text-foreground",
        info: "bg-background border-l-4 border-l-blue-500 border-border text-foreground",
      },
    },
    defaultVariants: { variant: "default" },
  }
)

const variantIcons: Record<string, React.ReactNode> = {
  success: <CheckCircle2Icon className="mt-0.5 size-4 shrink-0 text-green-500" />,
  error: <AlertCircleIcon className="mt-0.5 size-4 shrink-0 text-destructive" />,
  warning: <AlertTriangleIcon className="mt-0.5 size-4 shrink-0 text-yellow-500" />,
  info: <InfoIcon className="mt-0.5 size-4 shrink-0 text-blue-500" />,
}

interface ToastProps
  extends React.ComponentPropsWithoutRef<"div">,
    VariantProps<typeof toastVariants> {
  title?: string
  description?: string
  action?: React.ReactNode
  onClose?: () => void
}

const Toast = React.forwardRef<HTMLDivElement, ToastProps>(
  ({ className, variant = "default", title, description, action, onClose, children, ...props }, ref) => {
    return (
      <div
        ref={ref}
        data-slot="toast"
        data-variant={variant}
        role="alert"
        aria-live="polite"
        className={cn(toastVariants({ variant }), className)}
        {...props}
      >
        {variant && variant !== "default" && variantIcons[variant]}
        <div className="flex flex-1 flex-col gap-1">
          {title && (
            <div data-slot="toast-title" className="text-sm font-semibold leading-none">
              {title}
            </div>
          )}
          {description && (
            <div data-slot="toast-description" className="text-sm text-muted-foreground">
              {description}
            </div>
          )}
          {children}
          {action && <div data-slot="toast-action" className="mt-2">{action}</div>}
        </div>
        {onClose && (
          <button
            data-slot="toast-close"
            onClick={onClose}
            className="absolute top-2 right-2 inline-flex size-5 items-center justify-center rounded-md text-muted-foreground opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
            aria-label="Close"
          >
            <XIcon className="size-3.5" />
          </button>
        )}
      </div>
    )
  }
)
Toast.displayName = "Toast"

interface ToastViewportProps extends React.ComponentPropsWithoutRef<"div"> {
  position?: "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right"
}

const positionClasses: Record<NonNullable<ToastViewportProps["position"]>, string> = {
  "top-left": "top-4 left-4",
  "top-center": "top-4 left-1/2 -translate-x-1/2",
  "top-right": "top-4 right-4",
  "bottom-left": "bottom-4 left-4",
  "bottom-center": "bottom-4 left-1/2 -translate-x-1/2",
  "bottom-right": "bottom-4 right-4",
}

function ToastViewport({ className, position = "bottom-right", ...props }: ToastViewportProps) {
  return (
    <div
      data-slot="toast-viewport"
      className={cn(
        "fixed z-[100] flex max-h-screen w-full max-w-sm flex-col gap-2 p-4",
        positionClasses[position],
        className
      )}
      {...props}
    />
  )
}

type ToastEntry = ToastProps & {
  id: string
  duration?: number
}

interface ToastProviderContextValue {
  toasts: ToastEntry[]
  toast: (props: Omit<ToastEntry, "id">) => string
  dismiss: (id: string) => void
  dismissAll: () => void
}

const ToastContext = React.createContext<ToastProviderContextValue | null>(null)

function ToastProvider({ children, position = "bottom-right" }: { children: React.ReactNode; position?: ToastViewportProps["position"] }) {
  const [toasts, setToasts] = React.useState<ToastEntry[]>([])

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

  const dismissAll = React.useCallback(() => {
    setToasts([])
  }, [])

  const toast = React.useCallback(
    (props: Omit<ToastEntry, "id">) => {
      const id = Math.random().toString(36).slice(2)
      const duration = props.duration ?? 5000
      setToasts((prev) => [...prev, { ...props, id }])
      if (duration > 0) {
        setTimeout(() => dismiss(id), duration)
      }
      return id
    },
    [dismiss]
  )

  return (
    <ToastContext.Provider value={{ toasts, toast, dismiss, dismissAll }}>
      {children}
      <ToastViewport position={position}>
        {toasts.map((t) => {
          const { id, duration: _duration, ...rest } = t
          return (
            <Toast key={id} {...rest} onClose={() => dismiss(id)} />
          )
        })}
      </ToastViewport>
    </ToastContext.Provider>
  )
}

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

export { Toast, ToastProvider, ToastViewport, toastVariants, useToast }
export type { ToastEntry, ToastProps, ToastViewportProps }
