"use client";

import * as React from "react";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import { LayoutGroup, motion } from "motion/react";
import { ArrowLeft, Building2, ChevronsLeft, ChevronsRight, Menu, MoreHorizontal, Plus, Search } from "lucide-react";
import { cn } from "@/lib/utils";
import type { NavItem, QuickAction } from "@/lib/navigation";
import { Icon } from "@/components/icon";
import { Button } from "@/components/ui/button";
import { Avatar, Tooltip } from "@/components/ui/primitives";
import { Dialog, DrawerContent, DialogTitle } from "@/components/ui/dialog";
import { RouteProgress } from "@/components/motion/route-progress";
import { CommandPalette } from "./command-palette";
import { NotificationsBell } from "./notifications-bell";
import { UserMenu } from "./user-menu";
import { QuickCreate } from "./quick-create";
import { ConnectionStatus } from "./connection-status";
import { Presence } from "./presence";
import { ThemeSegment } from "./theme-segment";
import { ReservationDrawerProvider } from "@/components/reservations/reservation-drawer";

export interface ShellUser {
  id: string;
  fullName: string;
  email: string;
  avatarUrl: string | null;
  roleName: string;
  roleKey: string;
  isAdmin: boolean;
  permissions: string[];
}
export interface ShellBadges {
  notifications: number;
  tasks: number;
  cleaning: number;
}

const ShellContext = React.createContext<{ user: ShellUser; openPalette: () => void } | null>(null);
export function useShell() {
  const ctx = React.useContext(ShellContext);
  if (!ctx) throw new Error("useShell outside AppShell");
  return ctx;
}
export function usePermission() {
  const { user } = useShell();
  return (p: string) => user.isAdmin || user.permissions.includes(p);
}

const spring = { type: "spring", stiffness: 520, damping: 42, mass: 0.8 } as const;

/**
 * Application shell. Desktop: collapsible sidebar + glass top bar. Tablet:
 * icon rail. Phone: glass top bar with a contextual back button and a
 * floating tab bar with the quick-create action in the middle. The active
 * item glides between entries instead of jumping.
 */
export function AppShell({ user, nav, quickActions, business, badges, children }: { user: ShellUser; nav: NavItem[]; quickActions: QuickAction[]; business: { name: string; logoUrl: string | null }; badges: ShellBadges; children: React.ReactNode }) {
  const pathname = usePathname();
  const router = useRouter();
  const [collapsed, setCollapsed] = React.useState(false);
  const [mobileOpen, setMobileOpen] = React.useState(false);
  const [paletteOpen, setPaletteOpen] = React.useState(false);
  const [scrolled, setScrolled] = React.useState(false);

  React.useEffect(() => {
    try {
      setCollapsed(localStorage.getItem("lj_sidebar") === "collapsed");
    } catch {}
  }, []);
  const toggleCollapsed = () => {
    setCollapsed((c) => {
      try {
        localStorage.setItem("lj_sidebar", !c ? "collapsed" : "expanded");
      } catch {}
      return !c;
    });
  };
  React.useEffect(() => setMobileOpen(false), [pathname]);
  React.useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 8);
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  React.useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        setPaletteOpen((o) => !o);
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  const groups = React.useMemo(() => {
    const order = ["Operations", "Workforce", "Finance", "System", "Me"];
    const map = new Map<string, NavItem[]>();
    for (const item of nav) map.set(item.group, [...(map.get(item.group) ?? []), item]);
    return order.filter((g) => map.has(g)).map((g) => ({ name: g, items: map.get(g)! }));
  }, [nav]);

  const isActive = (href: string) => pathname === href || (href !== "/dashboard" && pathname.startsWith(href + "/")) || (href !== "/dashboard" && pathname.startsWith(href + "?"));
  const badgeFor = (item: NavItem) => (item.badgeKey ? badges[item.badgeKey] : 0);
  const current = nav.find((n) => isActive(n.href));
  const currentTitle = current?.label ?? "";
  const nested = pathname.split("/").filter(Boolean).length > 1 && !/^\/(settings)\//.test(pathname);
  const today = new Intl.DateTimeFormat("en", { weekday: "long", day: "numeric", month: "long" }).format(new Date());

  const mobileItems = nav.filter((n) => n.mobile).slice(0, 4);
  const showMore = nav.length > mobileItems.length;

  let navIndex = 0;
  const NavList = ({ compact, scope, animated }: { compact: boolean; scope: string; animated?: boolean }) => (
    <nav className="flex flex-1 flex-col gap-5 overflow-y-auto px-2.5 py-4 scrollbar-none" aria-label="Main">
      <LayoutGroup id={scope}>
        {groups.map((g) => (
          <div key={g.name}>
            {!compact ? <p className={cn("eyebrow mb-1.5 px-2.5 text-[10px]", animated && "animate-fade-in")}>{g.name}</p> : <div className="mx-3 mb-2 h-px bg-border" />}
            <ul className="space-y-0.5">
              {g.items.map((item) => {
                const active = isActive(item.href);
                const badge = badgeFor(item);
                const delay = animated ? 0.05 + navIndex++ * 0.028 : 0;
                const link = (
                  <Link
                    href={item.href}
                    className={cn(
                      "group relative flex items-center gap-2.5 rounded-lg px-2.5 py-2 text-[13px] font-medium transition-colors duration-200",
                      active ? "text-primary" : "text-fg-muted hover:text-fg",
                      compact && "justify-center px-0 py-2.5"
                    )}
                    aria-current={active ? "page" : undefined}
                  >
                    {active ? <motion.span layoutId={`${scope}-active`} transition={spring} className="absolute inset-0 rounded-lg bg-primary/10 shadow-[inset_0_0_0_1px_color-mix(in_oklab,var(--color-primary)_18%,transparent)] dark:bg-primary/15" aria-hidden /> : <span className="absolute inset-0 rounded-lg bg-surface-2 opacity-0 transition-opacity duration-200 group-hover:opacity-100" aria-hidden />}
                    <span className={cn("relative flex size-7 shrink-0 items-center justify-center rounded-md transition-all duration-200 [transition-timing-function:var(--ease-spring)] group-hover:scale-110", active ? "bg-primary text-primary-fg shadow-sm shadow-primary/30" : "bg-transparent text-fg-subtle group-hover:bg-surface-3 group-hover:text-fg")}>
                      <Icon name={item.icon} className="size-4" strokeWidth={active ? 2 : 1.75} />
                    </span>
                    {!compact ? <span className="relative truncate">{item.label}</span> : null}
                    {badge > 0 ? (
                      <span key={badge} className={cn("relative ml-auto rounded-full px-1.5 py-0.5 text-2xs font-semibold leading-none tabular animate-badge-pop", active ? "bg-primary text-primary-fg" : "bg-surface-3 text-fg-muted", compact && "absolute -right-0.5 -top-0.5 ml-0 bg-primary text-primary-fg")}>{badge > 99 ? "99+" : badge}</span>
                    ) : null}
                  </Link>
                );
                const inner = compact ? (
                  <Tooltip content={item.label} side="right" delay={0}>
                    {link}
                  </Tooltip>
                ) : (
                  link
                );
                return animated ? (
                  <motion.li key={item.href} initial={{ opacity: 0, x: -14 }} animate={{ opacity: 1, x: 0 }} transition={{ type: "spring", stiffness: 460, damping: 34, delay }}>
                    {inner}
                  </motion.li>
                ) : (
                  <li key={item.href}>{inner}</li>
                );
              })}
            </ul>
          </div>
        ))}
      </LayoutGroup>
    </nav>
  );

  const Brand = ({ compact }: { compact?: boolean }) => (
    <Link href="/dashboard" className={cn("group flex h-14 items-center gap-2.5 px-4", compact && "justify-center px-0")}>
      <span className="brand-tile flex size-8 shrink-0 items-center justify-center rounded-lg text-white transition-transform duration-300 [transition-timing-function:var(--ease-spring)] group-hover:rotate-[-6deg] group-hover:scale-105">
        <Building2 className="size-4" />
      </span>
      {!compact ? (
        <span className="min-w-0">
          <span className="block truncate font-display text-[17px] font-medium leading-tight tracking-tight text-fg">{business.name}</span>
          <span className="block text-[10px] font-medium uppercase tracking-[0.14em] text-fg-subtle">Property system</span>
        </span>
      ) : null}
    </Link>
  );

  const UserCard = ({ compact }: { compact?: boolean }) => (
    <Link href="/profile" className={cn("m-2 flex items-center gap-2.5 rounded-lg border border-border bg-surface-2/60 p-2 transition-all duration-200 hover:bg-surface-2 hover:border-border-strong", compact && "justify-center border-0 bg-transparent p-1")}>
      <Avatar name={user.fullName} src={user.avatarUrl} size="sm" online />
      {!compact ? (
        <span className="min-w-0">
          <span className="block truncate text-xs font-semibold text-fg">{user.fullName}</span>
          <span className="block truncate text-2xs text-fg-muted">{user.roleName}</span>
        </span>
      ) : null}
    </Link>
  );

  return (
    <ShellContext.Provider value={{ user, openPalette: () => setPaletteOpen(true) }}>
      <RouteProgress />
      <div className="flex min-h-dvh">
        {/* Desktop sidebar (lg+) — collapsible. Tablet (md) — icon rail. */}
        <aside className={cn("sticky top-0 hidden h-dvh shrink-0 flex-col border-r border-border bg-surface/70 backdrop-blur-xl transition-[width] duration-300 [transition-timing-function:var(--ease-out-expo)] md:flex", collapsed ? "lg:w-[72px]" : "lg:w-[248px]", "w-[72px]")}>
          <div className="hidden lg:block">
            <Brand compact={collapsed} />
          </div>
          <div className="lg:hidden">
            <Brand compact />
          </div>
          <div className="hidden lg:flex lg:min-h-0 lg:flex-1 lg:flex-col">
            <NavList compact={collapsed} scope="nav-desktop" />
          </div>
          <div className="flex min-h-0 flex-1 flex-col lg:hidden">
            <NavList compact scope="nav-rail" />
          </div>
          <div className="border-t border-border">
            <div className="hidden lg:block">
              <UserCard compact={collapsed} />
            </div>
            <div className="lg:hidden">
              <UserCard compact />
            </div>
            <div className="hidden px-2 pb-2 lg:block">
              <Button variant="ghost" size="sm" onClick={toggleCollapsed} className={cn("w-full justify-start text-fg-subtle", collapsed && "justify-center px-0")} aria-label={collapsed ? "Expand sidebar" : "Collapse sidebar"}>
                {collapsed ? <ChevronsRight /> : <ChevronsLeft />}
                {!collapsed ? <span>Collapse</span> : null}
              </Button>
            </div>
          </div>
        </aside>

        <div className="flex min-w-0 flex-1 flex-col">
          {/* Top bar */}
          <header className={cn("sticky top-0 z-30 flex h-14 items-center gap-2 px-3 transition-shadow duration-300 safe-top sm:px-5", "glass border-x-0 border-t-0", scrolled ? "shadow-sm" : "border-b-transparent")}>
            {nested ? (
              <Button variant="ghost" size="icon" className="md:hidden animate-scale-in" onClick={() => router.back()} aria-label="Back">
                <ArrowLeft />
              </Button>
            ) : (
              <Button variant="ghost" size="icon" className="md:hidden icon-nudge" onClick={() => setMobileOpen(true)} aria-label="Open menu">
                <Menu />
              </Button>
            )}
            <div className="flex min-w-0 flex-col md:hidden">
              <span key={currentTitle} className="truncate font-display text-base font-medium leading-tight animate-slide-up">
                {currentTitle || business.name}
              </span>
              <span className="truncate text-[10px] text-fg-subtle">{today}</span>
            </div>
            <div className="hidden min-w-0 items-baseline gap-2 md:flex">
              <p key={currentTitle} className="truncate text-sm font-semibold text-fg animate-slide-up">
                {currentTitle}
              </p>
              <p className="hidden truncate text-xs text-fg-subtle lg:block">{today}</p>
            </div>
            <div className="ml-auto flex items-center gap-1 sm:gap-2">
              <button
                type="button"
                onClick={() => setPaletteOpen(true)}
                className="group hidden h-9 w-64 items-center gap-2 rounded-full border border-border bg-surface/80 px-3.5 text-sm text-fg-subtle shadow-xs transition-all duration-300 [transition-timing-function:var(--ease-out-expo)] hover:w-80 hover:border-primary/40 hover:text-fg-muted hover:shadow-[0_0_0_4px_color-mix(in_oklab,var(--color-primary)_12%,transparent)] md:flex"
                aria-label="Search"
              >
                <Search className="size-4 transition-transform duration-300 group-hover:scale-110 group-hover:text-primary" />
                <span className="flex-1 text-left">Search or jump to…</span>
                <kbd className="rounded-md border border-border bg-surface-2 px-1.5 py-0.5 font-mono text-2xs text-fg-muted transition-colors group-hover:border-primary/30 group-hover:text-primary">⌘K</kbd>
              </button>
              <Button variant="ghost" size="icon" className="md:hidden icon-nudge" onClick={() => setPaletteOpen(true)} aria-label="Search">
                <Search />
              </Button>
              {quickActions.length ? <QuickCreate actions={quickActions} /> : null}
              <NotificationsBell initialUnread={badges.notifications} />
              <UserMenu user={user} />
            </div>
          </header>

          <main className="mx-auto w-full max-w-[1600px] flex-1 px-3 pt-4 pb-nav sm:px-5 sm:pt-5 md:pb-10 lg:px-8">
            {/* Page transition (fade + 6px lift). Keying on the pathname remounts the
                wrapper on every route change, which is what a route template.tsx used
                to do — done here instead, because a template makes the App Router's
                dev-mode layout router render its style list without keys. */}
            <div key={pathname} className="animate-page-in">
              <ReservationDrawerProvider>{children}</ReservationDrawerProvider>
            </div>
          </main>
        </div>
      </div>

      {/* Phone tab bar — floating, glass, thumb-reachable */}
      <nav className="fixed inset-x-3 bottom-[calc(0.75rem+env(safe-area-inset-bottom))] z-30 md:hidden" aria-label="Mobile">
        <LayoutGroup id="tabbar">
          <ul className="glass grid h-[60px] grid-cols-5 items-center rounded-2xl shadow-xl">
            {mobileItems.slice(0, 2).map((item) => (
              <MobileTab key={item.href} item={item} active={isActive(item.href)} badge={badgeFor(item)} />
            ))}
            <li className="flex justify-center">
              {quickActions.length ? (
                <QuickCreate
                  actions={quickActions}
                  sheet
                  trigger={
                    <button type="button" className="brand-tile group -mt-7 flex size-14 items-center justify-center rounded-full text-white ring-4 ring-bg transition-transform duration-300 [transition-timing-function:var(--ease-spring)] hover:scale-105 active:scale-95 data-[state=open]:rotate-45 data-[state=open]:scale-95" aria-label="Quick actions">
                      <Plus className="size-6" />
                    </button>
                  }
                />
              ) : (
                <Link href="/dashboard" className="brand-tile -mt-7 flex size-14 items-center justify-center rounded-full text-white ring-4 ring-bg">
                  <Building2 className="size-6" />
                </Link>
              )}
            </li>
            {mobileItems.slice(2, 4).map((item) => (
              <MobileTab key={item.href} item={item} active={isActive(item.href)} badge={badgeFor(item)} />
            ))}
            {mobileItems.length < 4 && showMore ? (
              <li>
                <button type="button" onClick={() => setMobileOpen(true)} className="flex w-full flex-col items-center gap-0.5 text-fg-muted">
                  <MoreHorizontal className="size-5" />
                  <span className="text-[10px] font-medium">More</span>
                </button>
              </li>
            ) : null}
          </ul>
        </LayoutGroup>
      </nav>

      {/* Mobile drawer */}
      <Dialog open={mobileOpen} onOpenChange={setMobileOpen}>
        <DrawerContent width="sm" side="left" phone="side" className="bg-surface/95 backdrop-blur-2xl">
          <DialogTitle className="sr-only">Navigation</DialogTitle>
          <div className="relative overflow-hidden border-b border-border px-3 pb-3 pt-[calc(0.5rem+env(safe-area-inset-top))]">
            <div className="pointer-events-none absolute inset-0" aria-hidden>
              <div className="absolute -left-16 -top-20 size-56 rounded-full bg-primary/15 blur-3xl" />
              <div className="absolute -right-10 -top-10 size-40 rounded-full bg-gold-500/15 blur-3xl" />
            </div>
            <div className="relative">
              <Brand />
              <button
                type="button"
                onClick={() => {
                  setMobileOpen(false);
                  setTimeout(() => setPaletteOpen(true), 180);
                }}
                className="mt-1 flex h-10 w-full items-center gap-2 rounded-xl border border-border bg-surface/80 px-3 text-sm text-fg-subtle shadow-xs transition hover:border-primary/40 active:scale-[0.98]"
                aria-label="Search"
              >
                <Search className="size-4" />
                <span className="flex-1 text-left">Search or jump to…</span>
                <kbd className="rounded-md border border-border bg-surface-2 px-1.5 py-0.5 font-mono text-2xs text-fg-muted">⌘K</kbd>
              </button>
            </div>
          </div>
          <div className="flex min-h-0 flex-1 flex-col">{mobileOpen ? <NavList compact={false} scope="nav-drawer" animated /> : null}</div>
          <div className="border-t border-border p-2 pb-[calc(0.5rem+env(safe-area-inset-bottom))]">
            <ThemeSegment className="mx-1 mb-1" />
            <UserCard />
            <p className="flex items-center gap-1.5 px-3 pb-1 text-2xs text-fg-subtle">
              <span className="live-dot" /> Live sync on · {business.name}
            </p>
          </div>
        </DrawerContent>
      </Dialog>

      <CommandPalette open={paletteOpen} onOpenChange={setPaletteOpen} nav={nav} quickActions={quickActions} />
      <ConnectionStatus />
      <Presence />
    </ShellContext.Provider>
  );
}

function MobileTab({ item, active, badge }: { item: NavItem; active: boolean; badge: number }) {
  return (
    <li>
      <Link href={item.href} className={cn("relative mx-auto flex w-full flex-col items-center gap-0.5 py-1.5 transition-colors duration-200 active:scale-95", active ? "text-primary" : "text-fg-muted")} aria-current={active ? "page" : undefined}>
        <span className="relative flex h-7 w-12 items-center justify-center rounded-full">
          {active ? <motion.span layoutId="tab-active" transition={spring} className="absolute inset-0 rounded-full bg-primary/12" aria-hidden /> : null}
          <Icon name={item.icon} className={cn("relative size-5 transition-transform duration-300 [transition-timing-function:var(--ease-spring)]", active && "scale-110")} strokeWidth={active ? 2.2 : 1.75} />
        </span>
        <span className="text-[10px] font-medium">{item.label}</span>
        {badge > 0 ? (
          <span key={badge} className="absolute right-1/2 top-0.5 translate-x-4 rounded-full bg-negative-500 px-1 text-[9px] font-bold leading-[14px] text-white ring-2 ring-surface animate-badge-pop">
            {badge}
          </span>
        ) : null}
      </Link>
    </li>
  );
}
