"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import Link from "next/link";
import Image from "next/image";
import { usePathname } from "next/navigation";
import { useCartCount } from "../lib/cart";
import { NewsletterModal } from "./NewsletterModal";
import { useCartFly } from "./CartFly";

const NAVBAR_HEIGHT = 100; // px — matches h-[6.25rem]
const SCROLL_DURATION = 200; // ms

function smoothScrollTo(targetY: number) {
  const startY = window.scrollY;
  const distance = targetY - startY;
  const startTime = performance.now();

  function step(now: number) {
    const elapsed = now - startTime;
    const progress = Math.min(elapsed / SCROLL_DURATION, 1);
    // ease-out cubic — not ease-in-out. Ease-in-out's cubic ease-in half
    // stays nearly flat for the animation's first ~150-200ms, which read
    // as a delay before the scroll visibly starts. Ease-out moves
    // immediately and only decelerates into the landing.
    const ease = 1 - (1 - progress) ** 3;
    window.scrollTo(0, startY + distance * ease);
    if (progress < 1) requestAnimationFrame(step);
  }

  requestAnimationFrame(step);
}

// "Shop" becomes an in-page anchor to the homepage's ProductSpotlight
// section (id="spotlight") instead of a real /shop navigation whenever
// exactly 1 product is active — same reasoning as the other anchor links,
// #werkzeuge/#ueber-bjoern already have (a full catalog grid is
// degenerate UX with only 1 item to show). Passed down from
// app/layout.tsx, which is the one place already fetching the product
// catalog for this decision.
function getNavLinks(singleActiveProduct: boolean) {
  return [
    { label: "Werkzeuge", href: "#werkzeuge" },
    { label: "Blog", href: "/blog" },
    { label: "Über Björn", href: "#ueber-bjoern" },
    { label: "Shop", href: singleActiveProduct ? "#spotlight" : "/shop" },
  ];
}

// "Werkzeuge" also covers standalone tool/product pages that live under
// the Home "Werkzeuge" section conceptually — /todo-cards (ToDo-Karten),
// /challenge (7-Tage-Challenge), and /newsletter (Impulse & Tipps) are
// all tools listed there, even though none of these routes is nested
// under /werkzeuge/. Their own Figma sources (page-todo-karten,
// page-weekly-impulses, and the 7-Tage-Challenge card in section-tools)
// mark "Werkzeuge" active in the nav for the same reason — confirmed by
// page-weekly-impulses's own breadcrumb ("Startseite › Werkzeuge ›
// Impulse & Tipps") and active-underline position, same as page-todo-karten's.
const WERKZEUGE_ROUTES = ["/todo-cards", "/challenge", "/newsletter"];

function isNavLinkActive(href: string, pathname: string, activeSection: string): boolean {
  if (href === "#werkzeuge") {
    return (
      WERKZEUGE_ROUTES.some((route) => pathname.startsWith(route)) ||
      (pathname === "/" && activeSection === "werkzeuge")
    );
  }
  if (href.startsWith("#")) {
    return pathname === "/" && activeSection === href.slice(1);
  }
  return pathname === href || pathname.startsWith(`${href}/`);
}

// Account icon — no Figma source exists for this yet (added outside the
// normal Figma-first workflow, see the assistant's own project notes on
// why: without it there was no reachable way to log in at all once the
// cart was empty and no recent order existed — /checkout's own login
// toggle never even renders in that state, see CheckoutContent.tsx's
// early "Warenkorb ist leer" return). Fetches auth state client-side via
// /api/account/me rather than through the server-rendered layout — this
// component's parent (app/layout.tsx) is otherwise static/ISR-cacheable,
// and reading the session cookie there (next/headers' cookies()) would
// force the entire site into per-request dynamic rendering just for this.
// `loggedIn === null` is the brief "not checked yet" state on first paint.
function AccountLink({ variant }: { variant: "icon" | "mobile" }) {
  const [loggedIn, setLoggedIn] = useState<boolean | null>(null);

  useEffect(() => {
    fetch("/api/account/me")
      .then((res) => setLoggedIn(res.ok))
      .catch(() => setLoggedIn(false));
  }, []);

  const href = loggedIn ? "/konto/bestellungen" : "/konto/login";

  if (variant === "mobile") {
    return (
      <Link
        href={href}
        className="min-h-11 flex items-center justify-center px-6 py-4 rounded-sm border border-[#868686] text-h4 font-bold text-text-primary hover:border-brand hover:text-brand active:scale-[0.97] transition-all"
      >
        {loggedIn ? "Mein Konto" : "Anmelden"}
      </Link>
    );
  }

  return (
    <Link
      href={href}
      aria-label={loggedIn ? "Mein Konto (eingeloggt)" : "Anmelden"}
      className="relative flex h-11 w-11 items-center justify-center shrink-0 active:scale-[0.9] transition-transform"
    >
      <svg viewBox="0 0 24 24" className="h-6 w-6 text-text-primary" fill="none" aria-hidden="true">
        <circle cx="12" cy="8" r="3.6" stroke="currentColor" strokeWidth="1.8" />
        <path d="M4.5 20c1.2-4 4-6 7.5-6s6.3 2 7.5 6" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
      </svg>
      {/* Only real "am I logged in?" signal on the site outside /konto
          itself — same brand-colored underline language as the desktop
          nav links' active-state indicator, so it reads as consistent
          rather than a new visual idiom. */}
      {loggedIn && <span aria-hidden className="absolute bottom-1 h-[2px] w-4 bg-brand rounded-full" />}
    </Link>
  );
}

// Cart icon + count badge — traced from the Figma Navbar/Default component's
// btn-cart (icon-cart 32x30 + cart-count-badge, node 4849:24). Visible at
// every breakpoint tier (unlike the nav links / CTA buttons, which move into
// the hamburger drawer below lg) since the cart is a primary nav affordance.
// Badge only renders once something is actually in the cart.
function CartLink() {
  const count = useCartCount();
  const { registerCartIcon, pendingCount } = useCartFly();
  const anchorRef = useRef<HTMLAnchorElement>(null);
  const [pulse, setPulse] = useState(false);
  const prevVisibleRef = useRef(0);
  const pathname = usePathname();

  // Held back by pendingCount while a ball is mid-flight, so the badge only
  // "counts up" once the ball visually lands here — not the instant the
  // button is clicked (real cart data itself updates instantly elsewhere,
  // this is purely the badge's own display value).
  const visibleCount = Math.max(0, count - pendingCount);

  useEffect(() => {
    registerCartIcon(anchorRef.current);
    return () => registerCartIcon(null);
  }, [registerCartIcon]);

  useEffect(() => {
    if (visibleCount > prevVisibleRef.current) {
      setPulse(true);
      const t = setTimeout(() => setPulse(false), 350);
      prevVisibleRef.current = visibleCount;
      return () => clearTimeout(t);
    }
    prevVisibleRef.current = visibleCount;
  }, [visibleCount]);

  return (
    <Link
      ref={anchorRef}
      href="/cart"
      onClick={(e) => {
        // Already on /cart — a real navigation here is a no-op, so treat
        // the click as "take me back to the top" instead of doing nothing.
        if (pathname === "/cart") {
          e.preventDefault();
          smoothScrollTo(0);
        }
      }}
      aria-label={visibleCount > 0 ? `Warenkorb, ${visibleCount} Artikel` : "Warenkorb"}
      className="relative flex h-11 w-11 items-center justify-center shrink-0 active:scale-[0.9] transition-transform"
    >
      <svg
        viewBox="0 0 32 30"
        className={"h-7 w-7 text-text-primary transition-transform duration-300 " + (pulse ? "scale-110" : "scale-100")}
        fill="none"
        aria-hidden="true"
      >
        <path
          d="M2,2 H6 L9.2,17.7 a2.4,2.4 0 0 0 2.4,2 h11.6 a2.4,2.4 0 0 0 2.4,-1.9 L28,7.5 H8"
          stroke="currentColor"
          strokeWidth="2"
          strokeLinecap="round"
          strokeLinejoin="round"
        />
        <circle cx="12" cy="25" r="1.6" fill="currentColor" />
        <circle cx="24" cy="25" r="1.6" fill="currentColor" />
      </svg>
      {visibleCount > 0 && (
        <span
          className={
            "absolute top-0 right-0 flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-brand px-1 text-[0.6875rem] font-bold leading-none text-white transition-transform duration-300 " +
            (pulse ? "scale-125" : "scale-100")
          }
        >
          {visibleCount > 99 ? "99+" : visibleCount}
        </span>
      )}
    </Link>
  );
}

export function Navbar({ singleActiveProduct }: { singleActiveProduct: boolean }) {
  const pathname = usePathname();
  const [scrolled, setScrolled] = useState(false);
  const [activeSection, setActiveSection] = useState("");
  const [mobileOpen, setMobileOpen] = useState(false);
  const [newsletterOpen, setNewsletterOpen] = useState(false);
  const panelRef = useRef<HTMLDivElement>(null);
  const hamburgerRef = useRef<HTMLButtonElement>(null);

  const navLinks = useMemo(() => getNavLinks(singleActiveProduct), [singleActiveProduct]);
  const anchorIds = useMemo(
    () => navLinks.filter((l) => l.href.startsWith("#")).map((l) => l.href.slice(1)),
    [navLinks]
  );

  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 8);
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  // Handles landing on "/#werkzeuge" etc. after a cross-page nav click
  // (e.g. clicking "Werkzeuge" from /todo-cards) or a direct URL load with
  // a hash. Next.js's own built-in hash-scroll-after-navigation doesn't
  // reliably apply the sticky navbar's height offset and can fire before
  // the just-mounted page's layout has settled — this reimplements it with
  // the exact same smoothScrollTo + NAVBAR_HEIGHT offset as the same-page
  // click handlers below, so behavior is identical either way. Runs
  // whenever pathname becomes "/" (covers both the initial load and a
  // client-side transition landing here), a short delay lets layout
  // settle first.
  //
  // The no-hash branch below matters just as much: since the Navbar lives
  // in the root layout (never unmounts across navigations), Next.js's
  // default Link scroll behavior treats "/" as already-visible and leaves
  // the current scrollY untouched instead of resetting to top (see
  // next/dist/docs .../link.md's "maintain scroll position" default).
  // Landing on Home from a page scrolled halfway down (e.g. clicking the
  // logo from a scrolled /shop) then visually "lands" wherever that old
  // offset happens to fall in Home's layout — often right around the
  // Werkzeuge section — instead of at the top. Forcing scrollTo(0, 0) here
  // makes a plain logo/Home navigation always start at the top, exactly
  // like the same-page click handler below already does.
  useEffect(() => {
    if (pathname !== "/") return;
    const hash = window.location.hash.slice(1);
    if (!anchorIds.includes(hash)) {
      window.scrollTo(0, 0);
      return;
    }
    const timer = setTimeout(() => {
      const el = document.getElementById(hash);
      if (el) {
        const top = el.getBoundingClientRect().top + window.scrollY - NAVBAR_HEIGHT;
        smoothScrollTo(top);
      }
    }, 50);
    return () => clearTimeout(timer);
  }, [pathname, anchorIds]);

  useEffect(() => {
    const onScroll = () => {
      // trigger line = 1/3 from top of viewport (= 2/3 from bottom)
      const triggerY = window.scrollY + NAVBAR_HEIGHT + (window.innerHeight - NAVBAR_HEIGHT) / 3;
      let current = "";
      for (const id of anchorIds) {
        const el = document.getElementById(id);
        if (!el) continue;
        const top = el.getBoundingClientRect().top + window.scrollY;
        if (top <= triggerY) current = id;
      }
      setActiveSection(current);
    };

    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, [anchorIds]);

  // Close on viewport resize past the structural breakpoint, so the drawer
  // never lingers open behind the (now visible) desktop nav. The hamburger
  // exists through both sub-768 ("Collapsed") and 768-1023 ("Collapsed-CTA")
  // tiers, and only disappears at lg (1024) — see Navbar section of the plan.
  useEffect(() => {
    const onResize = () => {
      if (window.innerWidth >= 1024) setMobileOpen(false);
    };
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  // Focus management: move focus into the panel on open, trap Tab within
  // it, close + return focus to the hamburger button on Escape.
  useEffect(() => {
    if (!mobileOpen) return;

    const panel = panelRef.current;
    const focusables = panel?.querySelectorAll<HTMLElement>(
      'a[href], button:not([disabled])'
    );
    focusables?.[0]?.focus({ preventScroll: true });

    const onKeyDown = (e: KeyboardEvent) => {
      if (e.key === "Escape") {
        e.preventDefault();
        setMobileOpen(false);
        hamburgerRef.current?.focus({ preventScroll: true });
        return;
      }
      if (e.key !== "Tab" || !focusables || focusables.length === 0) return;
      const first = focusables[0];
      const last = focusables[focusables.length - 1];
      if (e.shiftKey && document.activeElement === first) {
        e.preventDefault();
        last.focus({ preventScroll: true });
      } else if (!e.shiftKey && document.activeElement === last) {
        e.preventDefault();
        first.focus({ preventScroll: true });
      }
    };

    document.addEventListener("keydown", onKeyDown);
    return () => document.removeEventListener("keydown", onKeyDown);
  }, [mobileOpen]);

  const closeMobile = () => setMobileOpen(false);

  return (
    // Fragment, not just the <header> — NewsletterModal must NOT be a
    // descendant of it. `backdrop-blur-md` below is a `backdrop-filter`,
    // which (like `transform`) makes its element a new containing block
    // for `position: fixed` descendants per spec. Since the header only
    // gets that class once `scrolled` is true, the modal's `fixed inset-0`
    // backdrop silently stopped being fixed to the viewport and became
    // fixed to the 100px-tall header instead — centering math then ran
    // against that instead of the viewport, clipping the modal to the top
    // of the page. Exactly reproduced whenever the modal was opened while
    // scrolled (e.g. after clicking an anchor link), never at the very
    // top of the page (scrollY <= 8, no backdrop-blur yet) — which is why
    // it looked tied to "clicked an anchor first" rather than to scroll
    // position itself.
    <>
    <header
      className={`sticky top-0 z-50 w-full h-[6.25rem] flex flex-col transition-[background-color,backdrop-filter] duration-300 ${
        scrolled || mobileOpen
          ? "bg-bg-base/80 backdrop-blur-md"
          : "bg-bg-base"
      }`}
    >
      <div className="flex h-[6.25rem] w-full shrink-0 items-center px-8">
        <div className="w-full flex items-center justify-between">

          {/* Logo — real navigation to "/" from anywhere else; only when
              already on "/" does it become a same-page smooth-scroll-to-top
              instead (a full Link navigation there would be pointless).
              Previously always preventDefault()'d and silently
              history.replaceState()'d the URL to "/" without an actual
              navigation — from another page that just rewrote the URL bar
              while leaving that page's content on screen. */}
          <Link
            href="/"
            className="shrink-0"
            onClick={
              pathname === "/"
                ? (e) => {
                    e.preventDefault();
                    closeMobile();
                    smoothScrollTo(0);
                    history.replaceState(null, "", "/");
                  }
                : closeMobile
            }
          >
            <Image
              src="/logo.png"
              alt="einfach produktiv"
              width={181}
              height={61}
              priority
            />
          </Link>

          {/* Nav links — inline only at lg+ (1024px, full "Navbar/Default").
              Between md and lg ("Collapsed-CTA") they move into the
              hamburger drawer while the CTA buttons stay inline — matches
              Figma's Navbar-Mobile component set exactly, see the plan.
              Matches the Figma NavLink component's hover: text never
              changes color, an underline (brand, 2px x 40px) fades in on
              hover and stays on for the active section. */}
          <nav className="hidden lg:flex items-center gap-12">
            {navLinks.map((link) => {
              const isActive = isNavLinkActive(link.href, pathname, activeSection);
              const underline = (
                <span
                  className={`h-[2px] bg-brand transition-all duration-200 ${
                    isActive ? "w-10 opacity-100" : "w-full opacity-0 group-hover:w-10 group-hover:opacity-100"
                  }`}
                />
              );
              // Anchor links only get the custom in-page smooth-scroll
              // behavior while actually on "/" — its target section
              // doesn't exist on any other route. From elsewhere (e.g.
              // /todo-cards), a plain navigation to "/#werkzeuge" is correct
              // instead: the global `scroll-padding-top` in globals.css
              // already offsets for the sticky navbar on a native hash
              // landing, so no extra JS is needed for that case.
              const isHomeAnchor = link.href.startsWith("#") && pathname === "/";
              const resolvedHref = link.href.startsWith("#") && pathname !== "/" ? `/${link.href}` : link.href;
              return (
                <Link
                  key={link.href}
                  href={resolvedHref}
                  onClick={
                    isHomeAnchor
                      ? (e) => {
                          e.preventDefault();
                          const el = document.getElementById(link.href.slice(1));
                          if (el) {
                            const top = el.getBoundingClientRect().top + window.scrollY - NAVBAR_HEIGHT;
                            smoothScrollTo(top);
                          }
                          history.replaceState(null, "", link.href);
                        }
                      : undefined
                  }
                  className="group flex flex-col items-center gap-1 cursor-pointer"
                >
                  <span className="text-h4 font-semibold text-text-primary tracking-[0.01125rem] whitespace-nowrap">
                    {link.label}
                  </span>
                  {underline}
                </Link>
              );
            })}
          </nav>

          {/* Trailing controls — CTA buttons (md+), cart (always), hamburger
              (below lg). Grouped so spacing stays consistent as individual
              children hide/show across the three breakpoint tiers. */}
          <div className="flex items-center gap-2">
            <AccountLink variant="icon" />
            <CartLink />

            {/* CTA buttons — inline from md (768px) up, i.e. through both
                "Collapsed-CTA" and full Desktop tiers */}
            <div className="hidden md:flex items-center gap-3 p-2">
              {/* Opens the modal (matches the original Figma prototype:
                  Newsletter-Button → Overlay newsletter-overlay) instead of
                  navigating to /newsletter — that page is reached via the
                  Werkzeuge "Impulse & Tipps" card's "Anmelden" link instead,
                  a different, heavier entry point for a different context. */}
              <button
                type="button"
                onClick={() => setNewsletterOpen(true)}
                className="px-6 py-4 rounded-sm border border-[#868686] text-h4 font-bold text-text-primary whitespace-nowrap hover:border-brand hover:text-brand active:scale-[0.97] transition-all"
              >
                Newsletter
              </button>
              <Link
                href="/challenge"
                className="px-6 py-4 rounded-sm bg-brand text-h4 font-bold text-text-primary whitespace-nowrap hover:bg-brand-hover active:scale-[0.97] transition-all"
              >
                7-Tage-Challenge
              </Link>
            </div>

            {/* Hamburger — visible below lg (1024px): covers both the fully
                collapsed (<768) and "Collapsed-CTA" (768-1023) tiers, since
                the nav links live in the drawer through both. */}
            <button
              ref={hamburgerRef}
              type="button"
              aria-expanded={mobileOpen}
              aria-controls="mobile-nav-panel"
              aria-label={mobileOpen ? "Menü schließen" : "Menü öffnen"}
              onClick={() => setMobileOpen((v) => !v)}
              className="lg:hidden flex h-11 w-11 items-center justify-center shrink-0"
            >
              <span className="relative block h-4 w-6">
                <span
                  className={`absolute left-0 top-0 block h-0.5 w-6 bg-text-primary transition-transform duration-200 ${
                    mobileOpen ? "translate-y-[7px] rotate-45" : ""
                  }`}
                />
                <span
                  className={`absolute left-0 top-[7px] block h-0.5 w-6 bg-text-primary transition-opacity duration-200 ${
                    mobileOpen ? "opacity-0" : "opacity-100"
                  }`}
                />
                <span
                  className={`absolute left-0 top-[14px] block h-0.5 w-6 bg-text-primary transition-transform duration-200 ${
                  mobileOpen ? "-translate-y-[7px] -rotate-45" : ""
                }`}
              />
            </span>
            </button>
          </div>
        </div>
      </div>

      {/* Mobile drawer panel — toggleable below lg (see hamburger above) */}
      <div
        id="mobile-nav-panel"
        ref={panelRef}
        className={`lg:hidden w-full overflow-hidden transition-[max-height] duration-300 ease-in-out ${
          mobileOpen ? "max-h-[30rem]" : "max-h-0"
        }`}
      >
        <nav className="flex flex-col gap-6 px-8 pt-2 pb-6">
          {navLinks.map((link) => {
            const isActive = isNavLinkActive(link.href, pathname, activeSection);
            const isHomeAnchor = link.href.startsWith("#") && pathname === "/";
            const resolvedHref = link.href.startsWith("#") && pathname !== "/" ? `/${link.href}` : link.href;
            return link.href.startsWith("#") ? (
              <Link
                key={link.href}
                href={resolvedHref}
                onClick={
                  isHomeAnchor
                    ? (e) => {
                        e.preventDefault();
                        closeMobile();
                        const el = document.getElementById(link.href.slice(1));
                        if (el) {
                          const top = el.getBoundingClientRect().top + window.scrollY - NAVBAR_HEIGHT;
                          smoothScrollTo(top);
                        }
                        history.replaceState(null, "", link.href);
                      }
                    : closeMobile
                }
                className="min-h-11 flex flex-col justify-center gap-1 text-h4 font-semibold text-text-primary w-fit"
              >
                {link.label}
                <span
                  className={`h-[2px] bg-brand transition-opacity duration-200 ${
                    isActive ? "w-10 opacity-100" : "w-10 opacity-0"
                  }`}
                />
              </Link>
            ) : (
              <Link
                key={link.href}
                href={link.href}
                onClick={closeMobile}
                className="min-h-11 flex items-center text-h4 font-semibold text-text-primary"
              >
                {link.label}
              </Link>
            );
          })}
        </nav>
        <div className="flex flex-col gap-3 px-8 pb-8">
          <button
            type="button"
            onClick={() => {
              closeMobile();
              setNewsletterOpen(true);
            }}
            className="min-h-11 flex items-center justify-center px-6 py-4 rounded-sm border border-[#868686] text-h4 font-bold text-text-primary hover:border-brand hover:text-brand active:scale-[0.97] transition-all"
          >
            Newsletter
          </button>
          <Link
            href="/challenge"
            onClick={closeMobile}
            className="min-h-11 flex items-center justify-center px-6 py-4 rounded-sm bg-brand text-h4 font-bold text-text-primary hover:bg-brand-hover active:scale-[0.97] transition-all"
          >
            7-Tage-Challenge
          </Link>
          <div onClick={closeMobile}>
            <AccountLink variant="mobile" />
          </div>
        </div>
      </div>
    </header>

      <NewsletterModal open={newsletterOpen} onClose={() => setNewsletterOpen(false)} />
    </>
  );
}
