import { EnvelopeIcon, ExclamationCircleIcon, XMarkIcon } from "@heroicons/react/20/solid";
import { CheckCircleIcon } from "@heroicons/react/24/solid";
import { useSearchParams } from "@remix-run/react";
import { useEffect, useMemo } from "react";
import { useTypedLoaderData } from "remix-typedjson";
import { Toaster, toast } from "sonner";
import { type ToastMessageAction } from "~/models/message.server";
import { type loader } from "~/root";
import { cn } from "~/utils/cn";
import { Button, LinkButton } from "./Buttons";
import { Header2 } from "./Headers";
import { Paragraph } from "./Paragraph";

const defaultToastDuration = 5000;
const permanentToastDuration = 60 * 60 * 24 * 1000;

export function Toast() {
  const { toastMessage } = useTypedLoaderData<typeof loader>();
  useEffect(() => {
    if (!toastMessage) {
      return;
    }
    const { message, type, options } = toastMessage;

    const ephemeral = options.action ? false : options.ephemeral;

    toast.custom(
      (t) => (
        <ToastUI
          variant={type}
          message={message}
          t={t as string}
          title={options.title}
          action={options.action}
        />
      ),
      {
        duration: ephemeral ? defaultToastDuration : permanentToastDuration,
      }
    );
  }, [toastMessage]);

  return <Toaster />;
}

export function useToast() {
  return useMemo(
    () => ({
      success(message: string, options?: { title?: string; ephemeral?: boolean }) {
        const ephemeral = options?.ephemeral ?? true;
        toast.custom(
          (t) => (
            <ToastUI variant="success" message={message} t={t as string} title={options?.title} />
          ),
          { duration: ephemeral ? defaultToastDuration : permanentToastDuration }
        );
      },
      error(message: string, options?: { title?: string; ephemeral?: boolean }) {
        const ephemeral = options?.ephemeral ?? true;
        toast.custom(
          (t) => (
            <ToastUI variant="error" message={message} t={t as string} title={options?.title} />
          ),
          { duration: ephemeral ? defaultToastDuration : permanentToastDuration }
        );
      },
    }),
    []
  );
}

export function ToastUI({
  variant,
  message,
  t,
  toastWidth = 356, // Default width, matches what sonner provides by default
  title,
  action,
}: {
  variant: "error" | "success";
  message: string;
  t: string;
  toastWidth?: string | number;
  title?: string;
  action?: ToastMessageAction;
}) {
  return (
    <div
      className={cn(
        "self-end rounded-md border border-grid-bright bg-background-dimmed",
        variant === "success" && "border-success",
        variant === "error" && "border-error"
      )}
      style={{
        width: toastWidth,
      }}
    >
      <div
        className={cn("flex w-full gap-2 rounded-lg p-3", title ? "items-start" : "items-center")}
      >
        {variant === "success" ? (
          <CheckCircleIcon className={cn("size-4 min-w-4 text-success", title && "mt-1")} />
        ) : (
          <ExclamationCircleIcon className={cn("size-4 min-w-4 text-error", title && "mt-1")} />
        )}
        <div className="flex flex-col">
          {title && <Header2 className="pt-0">{title}</Header2>}
          <Paragraph
            variant={title ? "small/dimmed" : "small/bright"}
            className={title ? "pb-1 pt-0.5" : ""}
          >
            {message}
          </Paragraph>
          <Action action={action} toastId={t} className="my-2" />
        </div>
        <button
          className={cn(
            "-mr-1 ms-auto rounded p-2 text-text-dimmed transition hover:text-text-bright",
            title && "-mt-1"
          )}
          onClick={() => toast.dismiss(t)}
        >
          <XMarkIcon className="size-4" />
        </button>
      </div>
    </div>
  );
}

function Action({
  action,
  toastId,
  className,
}: {
  action?: ToastMessageAction;
  toastId: string;
  className?: string;
}) {
  const [_, setSearchParams] = useSearchParams();

  if (!action) return null;

  switch (action.action.type) {
    case "link": {
      return (
        <LinkButton
          className={className}
          variant={action.variant ?? "secondary/small"}
          to={action.action.path}
        >
          {action.label}
        </LinkButton>
      );
    }
    case "help": {
      const feedbackType = action.action.feedbackType;
      return (
        <Button
          className={className}
          variant={action.variant ?? "secondary/small"}
          LeadingIcon={EnvelopeIcon}
          onClick={() => {
            setSearchParams({
              feedbackPanel: feedbackType,
            });
            toast.dismiss(toastId);
          }}
        >
          {action.label}
        </Button>
      );
    }
  }
}
