"use client";

import Link from "next/link";
import { ChevronLeft, ChevronRight, LogOut, NotebookPen } from "lucide-react";
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";

import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { useSideNav } from "@/components/nav/side-nav-provider";
import { SideNavItem } from "@/components/nav/side-nav-item";
import { ProjectsNavSection } from "@/components/nav/projects-nav-section";
import { NAV_ITEMS, ADMIN_NAV_ITEM } from "@/components/nav/nav-items";
import { ThemeToggle } from "@/components/theme/theme-toggle";
import { logout } from "@/lib/actions/auth";
import { Role } from "@/lib/generated/prisma/enums";

/**
 * The signed-in user's circle at the bottom of the nav: their photo when
 * they've set one, otherwise the letter fallback -- and a link to the
 * Profile page either way.
 */
function UserAvatar({
  userName,
  userEmail,
  avatar,
  sizeClass,
}: {
  userName: string | null;
  userEmail: string;
  avatar: string | null;
  sizeClass: string;
}) {
  if (avatar) {
    return (
      // eslint-disable-next-line @next/next/no-img-element -- data-URL avatars, no image-optimization pipeline in this self-hosted app
      <img
        src={avatar}
        alt={userName ?? userEmail}
        className={`${sizeClass} shrink-0 rounded-full object-cover`}
      />
    );
  }
  const letter = (userName?.trim()[0] ?? userEmail[0] ?? "?").slice(0, 1);
  return (
    <span
      className={`${sizeClass} flex shrink-0 items-center justify-center rounded-full bg-primary/10 text-xs font-bold text-primary uppercase`}
    >
      {letter}
    </span>
  );
}

/**
 * The actual nav content, shared by the desktop aside and the mobile
 * hamburger drawer so the two never drift apart. `collapsed` is always
 * false in the drawer (a 288px-wide sheet has no room for icon-only mode).
 */
function SideNavContent({
  collapsed,
  userEmail,
  userName,
  avatar,
  role,
  themeMenu,
}: {
  collapsed: boolean;
  userEmail: string;
  userName: string | null;
  avatar: string | null;
  role: Role;
  // Where the theme picker menu opens from its trigger -- right of the
  // trigger in the desktop sidebar, below it in the mobile drawer (a
  // right-opening menu would run off the phone's right edge there).
  themeMenu: { side: "right" | "bottom"; align: "start" | "end" };
}) {
  const adminItem = role === Role.ADMIN ? [ADMIN_NAV_ITEM] : [];
  // The user's display label: their name when set, otherwise the email
  // (same as before profiles existed).
  const userLabel = userName || userEmail;

  return (
    <>
      <div className={cn("flex items-center gap-2.5 px-4 py-4", collapsed && "justify-center px-0")}>
        <span className="flex size-8 shrink-0 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-sm">
          <NotebookPen className="size-4.5" />
        </span>
        {!collapsed && (
          <span className="truncate font-heading text-[17px] font-bold tracking-tight">
            Organize
          </span>
        )}
      </div>

      <nav className="flex flex-1 flex-col gap-0.5 overflow-y-auto px-2.5 pt-1 pb-2">
        {NAV_ITEMS.map((item) => (
          <SideNavItem key={item.href} item={item} collapsed={collapsed} />
        ))}
        <ProjectsNavSection collapsed={collapsed} />
        {adminItem.map((item) => (
          <SideNavItem key={item.href} item={item} collapsed={collapsed} />
        ))}
      </nav>

      <div className="space-y-0.5 px-2.5 pb-2">
        <ThemeToggle collapsed={collapsed} menuSide={themeMenu.side} menuAlign={themeMenu.align} />

        {collapsed ? (
          <form action={logout}>
            <Tooltip>
              <TooltipTrigger
                render={
                  <Button variant="ghost" size="icon" type="submit" className="w-full">
                    <LogOut className="size-4" />
                  </Button>
                }
              />
              <TooltipContent side="right">Log out ({userEmail})</TooltipContent>
            </Tooltip>
          </form>
        ) : (
          <form action={logout}>
            <Button variant="ghost" type="submit" className="w-full justify-start gap-2.5">
              <LogOut className="size-4" />
              <span className="truncate">Log out</span>
            </Button>
          </form>
        )}
      </div>

      <div className={cn("flex items-center gap-2 border-t px-4 py-3", collapsed && "justify-center px-0")}>
        {collapsed ? (
          <Tooltip>
            <TooltipTrigger
              render={
                <Link href="/profile" aria-label={`View profile (${userLabel})`} />
              }
            >
              <UserAvatar
                userName={userName}
                userEmail={userEmail}
                avatar={avatar}
                sizeClass="size-7"
              />
            </TooltipTrigger>
            <TooltipContent side="right">{userLabel}</TooltipContent>
          </Tooltip>
        ) : (
          <Link
            href="/profile"
            className="flex min-w-0 flex-1 items-center gap-2"
            aria-label="View profile"
          >
            <UserAvatar
              userName={userName}
              userEmail={userEmail}
              avatar={avatar}
              sizeClass="size-7"
            />
            <span className="truncate text-[13px] font-medium text-muted-foreground">
              {userLabel}
            </span>
          </Link>
        )}
      </div>
    </>
  );
}

/**
 * Mobile (< md) hamburger drawer: the full side nav in a left sheet.
 * Tapping any link closes it; the backdrop and Escape close it too.
 */
function MobileNavDrawer({
  userEmail,
  userName,
  avatar,
  role,
}: {
  userEmail: string;
  userName: string | null;
  avatar: string | null;
  role: Role;
}) {
  const { mobileOpen, setMobileOpen } = useSideNav();

  return (
    <DialogPrimitive.Root open={mobileOpen} onOpenChange={setMobileOpen}>
      <DialogPrimitive.Portal>
        <DialogPrimitive.Backdrop
          className="fixed inset-0 z-40 bg-black/60 duration-100 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 md:hidden"
        />
        <DialogPrimitive.Popup
          onClick={(e) => {
            // Close on navigation -- links (nav items, projects) are the only
            // things that should dismiss it, not e.g. a theme switch.
            if ((e.target as HTMLElement).closest("a")) setMobileOpen(false);
          }}
          className={cn(
            "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[85vw] flex-col overflow-y-auto bg-sidebar text-sidebar-foreground shadow-xl duration-200 md:hidden",
            "data-open:animate-in data-open:fade-in-0 data-open:slide-in-from-left",
            "data-closed:animate-out data-closed:fade-out-0 data-closed:slide-out-to-left"
          )}
        >
          <DialogPrimitive.Title className="sr-only">Menu</DialogPrimitive.Title>
          <SideNavContent
            collapsed={false}
            userEmail={userEmail}
            userName={userName}
            avatar={avatar}
            role={role}
            themeMenu={{ side: "bottom", align: "end" }}
          />
        </DialogPrimitive.Popup>
      </DialogPrimitive.Portal>
    </DialogPrimitive.Root>
  );
}

export function SideNav({
  userEmail,
  userName,
  avatar,
  role,
}: {
  userEmail: string;
  userName: string | null;
  avatar: string | null;
  role: Role;
}) {
  const { collapsed, toggle } = useSideNav();

  return (
    <>
      <aside
        className={cn(
          "hidden h-screen flex-col border-r bg-sidebar text-sidebar-foreground transition-[width] duration-300 ease-out md:flex",
          collapsed ? "w-16" : "w-60"
        )}
      >
        <SideNavContent
          collapsed={collapsed}
          userEmail={userEmail}
          userName={userName}
          avatar={avatar}
          role={role}
          themeMenu={{ side: "right", align: "start" }}
        />

        <div className={cn("flex border-t px-2 py-1.5", collapsed ? "justify-center" : "justify-end")}>
          <Button variant="ghost" size="icon" onClick={toggle} aria-label="Toggle sidebar">
            {collapsed ? <ChevronRight className="size-4" /> : <ChevronLeft className="size-4" />}
          </Button>
        </div>
      </aside>

      <MobileNavDrawer userEmail={userEmail} userName={userName} avatar={avatar} role={role} />
    </>
  );
}
