"use client";

import type { MultiSessionAuthClient } from "@better-auth-ui/core/plugins/multi-session";
import { useAuth, useSession } from "@better-auth-ui/react";
import { useSetActiveSession } from "@better-auth-ui/react/plugins/multi-session";
import {
  ChevronsUpDown,
  LogIn,
  LogOut,
  Settings,
  UserPlus2,
} from "lucide-react";
import { isValidElement, type ReactElement, type ReactNode } from "react";

import { buttonVariants } from "@/components/ui/button";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { cn } from "@/lib/utils";
import { UserAvatar } from "./user-avatar";
import { UserView } from "./user-view";

export type UserButtonLinkVisibility =
  | "authenticated"
  | "unauthenticated"
  | "always";

export type UserButtonLink = {
  label: ReactNode;
  href: string;
  icon?: ReactNode;
  variant?: "default" | "destructive";
  visibility?: UserButtonLinkVisibility;
};

export type UserButtonProps = {
  className?: string;
  align?: "center" | "end" | "start" | undefined;
  side?: "top" | "right" | "bottom" | "left";
  sideOffset?: number;
  size?: "default" | "icon";
  variant?:
    | "default"
    | "destructive"
    | "ghost"
    | "link"
    | "outline"
    | "secondary";
  links?: (UserButtonLink | ReactElement)[];
  hideSettings?: boolean;
};

function renderUserLink(
  link: UserButtonLink | ReactElement,
  navigate: (options: { to: string; replace?: boolean }) => void,
  fallbackKey: string,
): ReactNode {
  if (isValidElement(link)) return link;

  const { label, href, icon, variant } = link;
  return (
    <DropdownMenuItem
      key={fallbackKey}
      variant={variant}
      onClick={() => navigate({ to: href })}
    >
      {icon}
      {label}
    </DropdownMenuItem>
  );
}

export function UserButton({
  className,
  align,
  side,
  sideOffset,
  size = "default",
  variant = "ghost",
  links,
  hideSettings = false,
}: UserButtonProps) {
  const { authClient, basePaths, viewPaths, localization, plugins, navigate } =
    useAuth<MultiSessionAuthClient>();

  const { isPending: settingActiveSession } = useSetActiveSession(authClient);
  const { data: session, isPending: sessionPending } = useSession(authClient);

  const userLinks = links?.flatMap((link, index) => {
    if (!isValidElement(link)) {
      const visibility = link.visibility ?? "always";
      if (visibility === "authenticated" && !session) return [];
      if (visibility === "unauthenticated" && session) return [];
    }
    return [
      renderUserLink(link, navigate, `user-button-link-${index.toString()}`),
    ];
  });

  // Whether anything renders between the user info label and the sign-out item, so the leading separator isn't shown with nothing to separate (see #439).
  const hasSessionMenuItems =
    (userLinks?.length ?? 0) > 0 ||
    !hideSettings ||
    plugins.some((plugin) => (plugin.userMenuItems?.length ?? 0) > 0);

  return (
    <DropdownMenu>
      <DropdownMenuTrigger
        aria-label={size === "icon" ? localization.auth.account : undefined}
        className={
          size === "icon"
            ? cn("rounded-full", className)
            : cn(
                buttonVariants({ variant, size: "lg" }),
                "py-2.5 h-auto font-normal",
                className,
              )
        }
      >
        {size === "icon" ? (
          <UserAvatar />
        ) : (
          <>
            {session || sessionPending || settingActiveSession ? (
              <UserView isPending={!!settingActiveSession} />
            ) : (
              <>
                <UserAvatar />

                <div className="grid flex-1 text-left text-sm leading-tight">
                  {localization.auth.account}
                </div>
              </>
            )}

            <ChevronsUpDown className="ml-auto size-4" />
          </>
        )}
      </DropdownMenuTrigger>

      <DropdownMenuContent
        className="min-w-40 md:min-w-56 max-w-[48svw]"
        side={side}
        sideOffset={sideOffset}
        align={align}
      >
        {session && (
          <>
            <DropdownMenuGroup>
              <DropdownMenuLabel className="text-sm font-normal">
                <UserView />
              </DropdownMenuLabel>
            </DropdownMenuGroup>

            {hasSessionMenuItems && <DropdownMenuSeparator />}
          </>
        )}

        {session ? (
          <>
            {userLinks}

            {!hideSettings && (
              <DropdownMenuItem
                onClick={() =>
                  navigate({
                    to: `${basePaths.settings}/${viewPaths.settings.account}`,
                  })
                }
              >
                <Settings className="text-muted-foreground" />

                {localization.settings.settings}
              </DropdownMenuItem>
            )}

            {plugins.flatMap((plugin) =>
              plugin.userMenuItems?.map((Item, index) => (
                <Item key={`${plugin.id}-${index.toString()}`} />
              )),
            )}

            <DropdownMenuSeparator />

            <DropdownMenuItem
              onClick={() =>
                navigate({
                  to: `${basePaths.auth}/${viewPaths.auth.signOut}`,
                })
              }
            >
              <LogOut className="text-muted-foreground" />

              {localization.auth.signOut}
            </DropdownMenuItem>
          </>
        ) : (
          <>
            {userLinks}

            <DropdownMenuItem
              onClick={() =>
                navigate({
                  to: `${basePaths.auth}/${viewPaths.auth.signIn}`,
                })
              }
            >
              <LogIn className="text-muted-foreground" />

              {localization.auth.signIn}
            </DropdownMenuItem>

            <DropdownMenuItem
              onClick={() =>
                navigate({
                  to: `${basePaths.auth}/${viewPaths.auth.signUp}`,
                })
              }
            >
              <UserPlus2 className="text-muted-foreground" />

              {localization.auth.signUp}
            </DropdownMenuItem>

            {plugins.flatMap((plugin) =>
              plugin.userMenuItems?.map((Item, index) => (
                <Item key={`${plugin.id}-${index.toString()}`} />
              )),
            )}
          </>
        )}
      </DropdownMenuContent>
    </DropdownMenu>
  );
}
