import { AriaToastProps, AriaToastRegionProps, useToast, useToastRegion } from "@react-aria/toast";
import { ToastQueue, ToastState, useToastQueue } from "@react-stately/toast";
import { X } from "lucide-react";
import React, { useRef } from "react";

import Button from "~/components/button";
import cn from "~/utils/cn";

interface ToastProps extends AriaToastProps<React.ReactNode> {
  state: ToastState<React.ReactNode>;
}

function Toast({ state, ...props }: ToastProps) {
  const ref = useRef<HTMLDivElement | null>(null);
  const { toastProps, contentProps, titleProps, closeButtonProps } = useToast(props, state, ref);

  return (
    <div
      {...toastProps}
      ref={ref}
      className={cn(
        "flex items-center justify-between gap-x-3 pl-4 pr-3",
        "text-white shadow-overlay rounded-lg py-3",
        "bg-mist-900 dark:bg-mist-950",
      )}
    >
      <div {...contentProps} className="flex flex-col gap-2">
        <div {...titleProps}>{props.toast.content}</div>
      </div>
      <Button
        {...closeButtonProps}
        aria-label="Close"
        className={cn(
          "rounded-full p-1",
          "bg-transparent hover:bg-mist-700",
          "dark:bg-transparent dark:hover:bg-mist-800",
        )}
      >
        <X className="h-4 w-4" />
      </Button>
    </div>
  );
}

interface ToastRegionProps extends AriaToastRegionProps {
  state: ToastState<React.ReactNode>;
}

function ToastRegion({ state, ...props }: ToastRegionProps) {
  const ref = useRef<HTMLDivElement | null>(null);
  const { regionProps } = useToastRegion(props, state, ref);

  return (
    <div
      {...regionProps}
      ref={ref}
      className={cn("fixed bottom-20 right-4", "flex flex-col gap-4")}
    >
      {state.visibleToasts.map((toast) => (
        <Toast key={toast.key} toast={toast} state={state} />
      ))}
    </div>
  );
}

export interface ToastProviderProps extends AriaToastRegionProps {
  queue: ToastQueue<React.ReactNode>;
}

export default function ToastProvider({ queue, ...props }: ToastProviderProps) {
  const state = useToastQueue(queue);

  return <>{state.visibleToasts.length > 0 && <ToastRegion {...props} state={state} />}</>;
}
