"use client";

import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { History, LogOut, Play, Settings, User as UserIcon } from "lucide-react";

import { SearchSheet, SearchTrigger, useSearchSheet } from "@/components/layout/search-sheet";
import { useSession } from "@/components/layout/session-provider";
import { AuthModal } from "@/components/auth/auth-modal";
import { DropdownMenu } from "@/components/ui/dropdown";
import { siteConfig } from "@/config/site";
import { cn } from "@/lib/utils";

/**
 * Transparent top header.
 *
 * Sits over the hero artwork on the homepage and over the page background
 * everywhere else. It is `fixed`, transparent, and reserves no space in the
 * document flow — the hero starts flush against the top of the viewport and
 * scrolls *under* the header, which is what keeps the top of the hero uncropped.
 *
 * Because the bar is transparent, the hero's own top scrim (`hero-scrim-top`) is
 * what makes the controls readable over artwork; the gradient below is only
 * enough to carry them on the non-hero routes, whose background is already dark.
 * Once the page is scrolled the bar takes a solid blurred surface, so the
 * controls never end up sitting over arbitrary content.
 *
 * Single owner of search: `useSearchSheet` registers a global `/` shortcut and an
 * Escape handler, so exactly one instance may be mounted at a time. The header is
 * that instance, and the floating nav deliberately ships no search control — see
 * `floating-nav.tsx`.
 */
export function SiteHeader() {
  const pathname = usePathname();
  const router = useRouter();
  const { user, signOut } = useSession();
  const sheet = useSearchSheet();
  const [scrolled, setScrolled] = useState(false);
  const [lastPath, setLastPath] = useState(pathname);
  const [authOpen, setAuthOpen] = useState(false);

  /* Close the search sheet on navigation, and drop the scrolled state. */
  if (pathname !== lastPath) {
    setLastPath(pathname);
    setScrolled(false);
    setAuthOpen(false);
    sheet.closeSheet();
  }

  /* Solid surface once the page moves, so the bar never floats over content. */
  useEffect(() => {
    const sync = () => setScrolled(window.scrollY > 8);
    sync();
    window.addEventListener("scroll", sync, { passive: true });
    return () => window.removeEventListener("scroll", sync);
  }, []);

  /*
    The account menu is built only for an authenticated visitor.

    This is a real branch, not a CSS toggle: for a guest `accountItems` is an
    empty array, so `DropdownMenu` is never even mounted — the guest path gets
    the "Sign in" button that opens the auth dialog instead. Settings, Watch
    history and Sign out all require a session, and both of their routes
    redirect an anonymous visitor to the login page, so exposing them without
    one would only ever be a dead end.
  */
  const accountItems = user
    ? [
        {
          id: "profile",
          label: (
            <span className="flex flex-col">
              <span className="font-bold text-ink">{user.displayName}</span>
              <span className="text-[11px] text-ink-muted">@{user.username}</span>
            </span>
          ),
          onSelect: () => router.push("/profile"),
        },
        {
          id: "settings",
          label: "Settings",
          icon: <Settings className="size-4" />,
          onSelect: () => router.push("/settings"),
        },
        {
          id: "history",
          label: "Watch history",
          icon: <History className="size-4" />,
          onSelect: () => router.push("/history"),
        },
        {
          id: "logout",
          label: "Sign out",
          icon: <LogOut className="size-4" />,
          onSelect: () => {
            /*
              `signOut()` clears the session in the provider and therefore
              re-renders this header as the guest variant immediately — no
              `router.refresh()` needed for the menu itself. The push and refresh
              afterwards drop any page that was only reachable while signed in.
            */
            void signOut().then(() => {
              router.push("/");
              router.refresh();
            });
          },
        },
      ]
    : [];

  return (
    <>
      <header
        /*
          `pointer-events-none` on the bar with `pointer-events-auto` per control,
          so the strip itself never swallows a click meant for the hero beneath
          it. The gradient is the only thing painting over the artwork.
        */
        className={cn(
          "pointer-events-none fixed inset-x-0 top-0 z-[550] transition-colors duration-300",
          scrolled
            ? "border-b border-white/10 bg-bg/85 backdrop-blur-xl backdrop-saturate-150"
            : "bg-linear-to-b from-black/70 via-black/25 to-transparent",
        )}
      >
        <div className="flex h-14 w-full items-center justify-between gap-3 px-4 sm:h-16 sm:px-6 lg:px-8">
          {/* LEFT — wordmark */}
          <Link
            href="/"
            aria-label={`${siteConfig.name} home`}
            className="pointer-events-auto group flex shrink-0 items-center gap-2 rounded-pill"
          >
            <span
              className={cn(
                "grid size-8 shrink-0 place-items-center rounded-lg text-black shadow-lg sm:size-9",
                "bg-linear-to-br from-brand-400 to-brand-600 ring-1 ring-white/25",
                "transition-transform duration-300 group-hover:scale-105 motion-reduce:transform-none",
              )}
              aria-hidden
            >
              <Play className="size-4 fill-black sm:size-[18px]" />
            </span>
            <span className="font-display text-[17px] font-extrabold tracking-tight text-white drop-shadow-[0_2px_8px_rgba(0,0,0,0.7)] sm:text-xl">
              {siteConfig.shortName}
            </span>
          </Link>

          {/* RIGHT — search, then the account control */}
          <div className="flex shrink-0 items-center gap-1.5 sm:gap-2.5">
            <SearchTrigger
              onClick={sheet.openSheet}
              label="Search titles"
              className={cn(
                "pointer-events-auto grid size-9 shrink-0 place-items-center rounded-full sm:size-10",
                "text-white/80 transition-all duration-300 hover:bg-white/15 hover:text-white",
                "active:scale-90 motion-reduce:active:scale-100",
              )}
            />

            {/*
              Signed in and signed out are two genuinely different controls, not
              one menu with items hidden. A guest gets the button that opens the
              auth dialog; only an authenticated visitor gets the account
              dropdown, because Settings, Watch history and Sign out are all
              meaningless — and unreachable — without a session. Nothing is
              hidden with CSS: the items are simply never built.
            */}
            {user ? (
              <DropdownMenu
                label="Account"
                align="end"
                items={accountItems}
                /*
                  The header is `pointer-events-none` so the strip never covers
                  the hero. The panel has to opt back in, or every menu item is
                  rendered but unclickable — the trigger button alone is not
                  enough, because the panel is a sibling of the button inside
                  this wrapper.
                */
                className="pointer-events-auto"
              >
                {({ open, toggle, id }) => (
                  <button
                    type="button"
                    id={id}
                    onClick={toggle}
                    aria-expanded={open}
                    aria-haspopup="menu"
                    aria-label="Account menu"
                    className={cn(
                      "grid size-9 shrink-0 place-items-center rounded-full text-[12px] font-bold sm:size-10",
                      "bg-linear-to-br from-brand-500 to-brand-700 text-white ring-2 transition-all duration-300",
                      "hover:ring-white/40 active:scale-90 motion-reduce:active:scale-100",
                      open ? "ring-white/50" : "ring-white/15",
                    )}
                  >
                    {user.displayName.slice(0, 1).toUpperCase()}
                  </button>
                )}
              </DropdownMenu>
            ) : (
              <button
                type="button"
                onClick={() => setAuthOpen(true)}
                aria-label="Sign in"
                aria-haspopup="dialog"
                className={cn(
                  "pointer-events-auto inline-flex h-9 shrink-0 items-center gap-1.5 rounded-pill px-3 sm:h-10 sm:px-4",
                  "text-[13px] font-bold text-white/90 transition-all duration-300 sm:text-sm",
                  "bg-white/10 ring-1 ring-white/15 backdrop-blur-md",
                  "hover:bg-white/20 hover:text-white active:scale-95 motion-reduce:active:scale-100",
                )}
              >
                <UserIcon className="size-4 sm:size-[18px]" />
                <span aria-hidden className="hidden sm:inline">
                  Sign in
                </span>
              </button>
            )}
          </div>
        </div>
      </header>

      {sheet.open ? <SearchSheet onClose={sheet.closeSheet} /> : null}

      {/*
        The auth dialog is mounted only while it is open, so the portal — and the
        portal subtree — never exists in the tree for the 99% of visits that
        never touch "Sign in". `/login` and `/register` still stand on their own
        as deep-linkable routes; `lib/require-session.ts` and
        `add-to-list-button.tsx` both redirect to `/login`, which remains a
        working entry point to the same API.
      */}
      {authOpen ? <AuthModal open onClose={() => setAuthOpen(false)} /> : null}
    </>
  );
}
