import {
  createContext,
  useContext,
  useState,
  useCallback,
  type ReactNode,
  type HTMLAttributes,
  type ReactElement,
} from "react";

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

export interface Toast {
  id: string;
  message: string;
  variant?: ToastVariant;
  duration?: number;
}

export interface ToastContextValue {
  showToast: (message: string, variant?: ToastVariant, duration?: number) => void;
  removeToast: (id: string) => void;
}

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

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

export interface ToastProviderProps {
  children: ReactNode;
}

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

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

  const showToast = useCallback(
    (message: string, variant: ToastVariant = "info", duration = 5000) => {
      const id = `toast-${String(Date.now())}-${Math.random().toString(36).substring(2, 11)}`;
      const newToast: Toast = { id, message, variant, duration };

      setToasts((prev) => [...prev, newToast]);

      if (duration > 0) {
        setTimeout(() => {
          removeToast(id);
        }, duration);
      }
    },
    [removeToast]
  );

  return (
    <ToastContext.Provider value={{ showToast, removeToast }}>
      {children}
      <ToastContainer toasts={toasts} onRemove={removeToast} />
    </ToastContext.Provider>
  );
}

export interface ToastContainerProps extends HTMLAttributes<HTMLDivElement> {
  toasts: Toast[];
  onRemove: (id: string) => void;
}

function ToastContainer({
  toasts,
  onRemove,
  className = "",
}: ToastContainerProps): ReactElement | null {
  if (toasts.length === 0) return null;

  return (
    <div
      className={`fixed bottom-4 right-4 z-50 flex flex-col gap-2 ${className}`}
      role="alert"
      aria-live="polite"
    >
      {toasts.map((toast) => (
        <ToastItem key={toast.id} toast={toast} onRemove={onRemove} />
      ))}
    </div>
  );
}

interface ToastItemProps {
  toast: Toast;
  onRemove: (id: string) => void;
}

interface ToastVariantStyle {
  background: string;
  border: string;
  color: string;
}

const variantStyles: Record<ToastVariant, ToastVariantStyle> = {
  success: {
    background: "rgba(20,184,166,0.15)",
    border: "1px solid rgba(20,184,166,0.35)",
    color: "var(--success)",
  },
  error: {
    background: "rgba(229,72,77,0.15)",
    border: "1px solid rgba(229,72,77,0.35)",
    color: "var(--danger)",
  },
  warning: {
    background: "rgba(245,158,11,0.15)",
    border: "1px solid rgba(245,158,11,0.35)",
    color: "var(--warn)",
  },
  info: {
    background: "rgba(47,128,255,0.15)",
    border: "1px solid rgba(47,128,255,0.35)",
    color: "var(--info)",
  },
};

function ToastItem({ toast, onRemove }: ToastItemProps): ReactElement {
  const vStyle = variantStyles[toast.variant ?? "info"];

  const icon: Record<ToastVariant, ReactNode> = {
    success: (
      <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
        <path
          fillRule="evenodd"
          d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
          clipRule="evenodd"
        />
      </svg>
    ),
    error: (
      <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
        <path
          fillRule="evenodd"
          d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
          clipRule="evenodd"
        />
      </svg>
    ),
    warning: (
      <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
        <path
          fillRule="evenodd"
          d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
          clipRule="evenodd"
        />
      </svg>
    ),
    info: (
      <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
        <path
          fillRule="evenodd"
          d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
          clipRule="evenodd"
        />
      </svg>
    ),
  };

  return (
    <div
      className="rounded-md px-4 py-3 flex items-center gap-3 min-w-[300px] max-w-md"
      style={{
        background: vStyle.background,
        border: vStyle.border,
        color: vStyle.color,
      }}
      role="alert"
    >
      <span className="flex-shrink-0">{icon[toast.variant ?? "info"]}</span>
      <span className="flex-1 text-sm font-medium">{toast.message}</span>
      <button
        onClick={() => {
          onRemove(toast.id);
        }}
        className="flex-shrink-0 opacity-70 hover:opacity-100 transition-opacity p-0.5 rounded"
        aria-label="Close notification"
      >
        <svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
          <path
            fillRule="evenodd"
            d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
            clipRule="evenodd"
          />
        </svg>
      </button>
    </div>
  );
}

// Helper function to show toasts outside of React components
let toastContextValue: ToastContextValue | null = null;

export function setToastContext(context: ToastContextValue | null): void {
  toastContextValue = context;
}

export interface ToastOptions {
  variant?: ToastVariant;
  duration?: number;
}

export function toast(message: string, options?: ToastOptions): void {
  if (!toastContextValue) {
    console.warn("Toast context not available. Make sure ToastProvider is mounted.");
    return;
  }
  toastContextValue.showToast(message, options?.variant ?? "info", options?.duration ?? 5000);
}
