import { useEffect, useMemo, useState, type ReactNode } from "react";
import { Link, useLocation, useNavigate } from "@tanstack/react-router";
import {
  Sun,
  Moon,
  Languages,
  Newspaper,
  TrendingUp,
  Building2,
  Target,
  Settings2,
  LogOut,
  RefreshCw,
  MapPin,
  Loader2,
  Menu,
  X,
  Stethoscope,
  MessageSquare,
  Plus,
  Trash2,
  ChevronsUpDown,
  Layers,
  Check,
  
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { useAuth } from "@/hooks/useAuth";
import { useSettings, useT } from "@/hooks/useSettings";
import { useHotels } from "@/hooks/useHotels";
import { supabase } from "@/integrations/supabase/client";
import { toast } from "sonner";
import type { Hotel } from "@/lib/hotel";
import { UserMenu } from "@/components/UserMenu";
import { CreditsBadge } from "@/components/CreditsBadge";
import { useActionPlanSummary } from "@/hooks/useActionPlanSummary";

type NavItem = {
  to: "/" | "/industry" | "/competitors" | "/actions" | "/self-examination" | "/ask";
  label: string;
  icon: typeof Newspaper;
  description: string;
  i18nKey: string;
};

function navItems(t: (k: string, f?: string) => string): NavItem[] {
  return [
    { to: "/", label: t("nav.today"), icon: Newspaper, description: t("nav.today.desc"), i18nKey: "today" },
    { to: "/industry", label: t("nav.industry"), icon: TrendingUp, description: t("nav.industry.desc"), i18nKey: "industry" },
    { to: "/competitors", label: t("nav.competitors"), icon: Building2, description: t("nav.competitors.desc"), i18nKey: "competitors" },
    { to: "/self-examination", label: t("nav.selfexam"), icon: Stethoscope, description: t("nav.selfexam.desc"), i18nKey: "selfexam" },
    { to: "/actions", label: t("nav.actions"), icon: Target, description: t("nav.actions.desc"), i18nKey: "actions" },
    { to: "/ask", label: t("nav.ask"), icon: MessageSquare, description: t("nav.ask.desc"), i18nKey: "ask" },
  ];
}

export function AppShell({
  children,
  hotel,
  isLoading,
  onRefresh,
}: {
  children: ReactNode;
  hotel: Hotel | null;
  isLoading: boolean;
  onRefresh: () => void;
}) {
  const { signOut } = useAuth();
  const { theme, lang, toggleTheme, toggleLang } = useSettings();
  const t = useT();
  const NAV = navItems(t);
  const navigate = useNavigate();
  const location = useLocation();
  const [drawerOpen, setDrawerOpen] = useState(false);
  const [deleteOpen, setDeleteOpen] = useState(false);
  const [removeOpen, setRemoveOpen] = useState(false);

  const { hotels, isAllHotels, selectedHotelId, selectHotel } = useHotels();
  const planSummary = useActionPlanSummary({ hotelId: hotel?.id ?? null });
  const NAV_LIVE = NAV.map((n) =>
    n.to === "/actions"
      ? {
          ...n,
          description:
            planSummary.total > 0
              ? `${planSummary.done}/${planSummary.total} ${lang === "zh" ? "已完成" : "done"}`
              : n.description,
        }
      : n,
  );

  // Keep safe-area insets accurate across orientation changes AND dynamic
  // browser chrome events (iOS URL bar collapsing/expanding on scroll, soft
  // keyboard show/hide). We mirror env(safe-area-inset-*) into CSS custom
  // properties (--safe-top/right/bottom/left) measured from a probe element,
  // so padding tracks the *actual* current insets even when Safari is slow to
  // recompute env() values.
  useEffect(() => {
    if (typeof window === "undefined") return;
    const root = document.documentElement;

    // Hidden probe to read live env() values via getComputedStyle.
    const probe = document.createElement("div");
    probe.setAttribute("aria-hidden", "true");
    probe.style.cssText =
      "position:fixed;top:0;left:0;width:0;height:0;pointer-events:none;visibility:hidden;" +
      "padding-top:env(safe-area-inset-top);padding-right:env(safe-area-inset-right);" +
      "padding-bottom:env(safe-area-inset-bottom);padding-left:env(safe-area-inset-left);";
    document.body.appendChild(probe);

    const sync = () => {
      requestAnimationFrame(() => {
        const cs = getComputedStyle(probe);
        root.style.setProperty("--safe-top", cs.paddingTop || "0px");
        root.style.setProperty("--safe-right", cs.paddingRight || "0px");
        root.style.setProperty("--safe-bottom", cs.paddingBottom || "0px");
        root.style.setProperty("--safe-left", cs.paddingLeft || "0px");
        // Nudge layout so dvh / inset-bound padding repaints together.
        const prev = root.style.minHeight;
        root.style.minHeight = "100.0001dvh";
        void root.offsetHeight;
        root.style.minHeight = prev;
      });
    };

    sync();
    window.addEventListener("orientationchange", sync);
    window.addEventListener("resize", sync);
    window.addEventListener("scroll", sync, { passive: true });
    window.addEventListener("pageshow", sync);
    const mql = window.matchMedia("(orientation: portrait)");
    mql.addEventListener?.("change", sync);
    const vv = window.visualViewport;
    vv?.addEventListener("resize", sync);
    vv?.addEventListener("scroll", sync);

    return () => {
      window.removeEventListener("orientationchange", sync);
      window.removeEventListener("resize", sync);
      window.removeEventListener("scroll", sync);
      window.removeEventListener("pageshow", sync);
      mql.removeEventListener?.("change", sync);
      vv?.removeEventListener("resize", sync);
      vv?.removeEventListener("scroll", sync);
      probe.remove();
    };
  }, []);

  const dateLabel = useMemo(
    () =>
      new Date().toLocaleDateString(lang === "zh" ? "zh-CN" : "en-US", {
        weekday: "long",
        month: "long",
        day: "numeric",
        year: "numeric",
      }),
    [lang],
  );

  async function handleSignOut() {
    await signOut();
    navigate({ to: "/login" });
  }

  function isActive(to: NavItem["to"]) {
    return to === "/" ? location.pathname === "/" : location.pathname.startsWith(to);
  }

  const sidebar = (
    <div className="flex h-full flex-col overflow-y-auto rounded-none border-0 bg-card/80 p-5 shadow-none backdrop-blur-sm lg:rounded-2xl lg:border lg:bg-card/60 lg:shadow-[var(--shadow-elegant)]">
      <Link
        to="/"
        onClick={() => setDrawerOpen(false)}
        className="mb-6 flex items-center gap-3"
      >
        <div className="flex h-9 w-9 items-center justify-center rounded-full bg-brand text-primary-foreground">
          <Sun className="h-4 w-4" />
        </div>
        <div className="min-w-0">
          <div className="font-serif text-lg font-semibold leading-tight text-brand">
            {t("shell.brand")}
          </div>
          <div className="truncate text-[10px] uppercase tracking-[0.18em] text-muted-foreground">
            {dateLabel}
          </div>
        </div>
      </Link>

      {/* Hotel switcher */}
      <DropdownMenu>
        <DropdownMenuTrigger asChild>
          <button className="mb-4 flex w-full items-center justify-between gap-2 rounded-xl border bg-background/60 px-3 py-2 text-left transition-colors hover:bg-muted/50">
            <div className="flex min-w-0 items-center gap-2">
              {isAllHotels ? (
                <Layers className="h-4 w-4 shrink-0 text-brand" />
              ) : (
                <Building2 className="h-4 w-4 shrink-0 text-brand" />
              )}
              <div className="min-w-0">
                <div className="text-[10px] uppercase tracking-wider text-muted-foreground">
                  {t("shell.property")}
                </div>
                <div className="truncate font-serif text-sm font-medium text-foreground">
                  {isAllHotels
                    ? t("shell.allHotels")
                    : hotel?.hotel_name ?? t("shell.allHotels")}
                </div>
              </div>
            </div>
            <ChevronsUpDown className="h-4 w-4 shrink-0 text-muted-foreground" />
          </button>
        </DropdownMenuTrigger>
        <DropdownMenuContent align="start" className="w-64">
          <DropdownMenuLabel>{t("shell.property")}</DropdownMenuLabel>
          <DropdownMenuItem
            onClick={() => {
              selectHotel(null);
              setDrawerOpen(false);
            }}
            className="gap-2"
          >
            <Layers className="h-4 w-4" />
            <span className="flex-1 truncate">{t("shell.allHotels")}</span>
            {isAllHotels ? <Check className="h-4 w-4 text-brand" /> : null}
          </DropdownMenuItem>
          <DropdownMenuSeparator />
          {hotels.map((h) => (
            <DropdownMenuItem
              key={h.id}
              onClick={() => {
                selectHotel(h.id);
                setDrawerOpen(false);
              }}
              className="items-start gap-2 py-2"
            >
              <Building2 className="mt-0.5 h-4 w-4 shrink-0" />
              <div className="flex min-w-0 flex-1 flex-col leading-tight">
                <span className="truncate text-sm">{h.hotel_name}</span>
                <span className="truncate text-[10px] text-muted-foreground">{h.location}</span>
              </div>
              {selectedHotelId === h.id ? <Check className="mt-0.5 h-4 w-4 shrink-0 text-brand" /> : null}
            </DropdownMenuItem>
          ))}
          <DropdownMenuSeparator />
          <DropdownMenuItem
            onClick={() => {
              navigate({ to: "/onboarding" });
              setDrawerOpen(false);
            }}
            className="gap-2 text-brand"
          >
            <Plus className="h-4 w-4" />
            {t("shell.addHotel")}
          </DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>

      <nav className="flex flex-col gap-1">
        {NAV_LIVE.map((item) => {
          const active = isActive(item.to);
          const Icon = item.icon;
          return (
            <Link
              key={item.to}
              to={item.to}
              onClick={() => setDrawerOpen(false)}
              className={`group flex items-center gap-3 rounded-xl px-3 py-2.5 text-sm transition-colors ${
                active
                  ? "bg-brand text-primary-foreground shadow-sm"
                  : "text-foreground hover:bg-brand-soft/40"
              }`}
            >
              <Icon
                className={`h-4 w-4 shrink-0 ${
                  active ? "text-primary-foreground" : "text-brand"
                }`}
              />
              <div className="min-w-0 flex-1">
                <div className="font-medium leading-tight">{item.label}</div>
                <div
                  className={`truncate text-[10px] uppercase tracking-wider ${
                    active ? "text-primary-foreground/70" : "text-muted-foreground"
                  }`}
                >
                  {item.description}
                </div>
              </div>
            </Link>
          );
        })}
      </nav>

      {hotel ? (
        <div className="mt-6 rounded-xl border bg-background/50 p-3">
          <div className="text-[10px] uppercase tracking-wider text-muted-foreground">
            {t("shell.property")}
          </div>
          <div className="mt-1 truncate font-serif text-base font-medium text-foreground">
            {hotel.hotel_name}
          </div>
          <div className="mt-1 flex items-center gap-1 text-xs text-muted-foreground">
            <MapPin className="h-3 w-3 shrink-0" />
            <span className="truncate">{hotel.location}</span>
          </div>
          <div className="mt-2 flex flex-wrap gap-x-3 gap-y-0.5 text-[10px] uppercase tracking-wider text-muted-foreground">
            {hotel.rooms ? <span>{hotel.rooms} {t("shell.rooms")}</span> : null}
            <span>{hotel.radius_km} {t("shell.kmWatch")}</span>
          </div>
        </div>
      ) : (
        <div className="mt-6 rounded-xl border border-dashed bg-background/40 p-3 text-xs text-muted-foreground">
          {hotels.length === 0 ? t("portfolio.empty") : t("portfolio.subtitleHint")}
        </div>
      )}

      <div className="mt-auto flex flex-col gap-1.5 pt-6">
        <Button
          size="sm"
          variant="outline"
          onClick={() => {
            onRefresh();
            setDrawerOpen(false);
          }}
          disabled={isLoading || isAllHotels || !hotel}
          className="w-full justify-start gap-2"
        >
          {isLoading ? (
            <Loader2 className="h-4 w-4 animate-spin" />
          ) : (
            <RefreshCw className="h-4 w-4" />
          )}
          {t("shell.refresh")}
        </Button>
        {hotel ? (
          <>
            <Button
              asChild
              size="sm"
              variant="ghost"
              className="w-full justify-start gap-2 text-muted-foreground"
            >
              <Link
                to="/onboarding"
                search={{ hotelId: hotel.id } as never}
                onClick={() => setDrawerOpen(false)}
              >
                <Settings2 className="h-4 w-4" />
                {t("shell.editHotel")}
              </Link>
            </Button>
            <Button
              size="sm"
              variant="ghost"
              onClick={() => {
                setRemoveOpen(true);
                setDrawerOpen(false);
              }}
              className="w-full justify-start gap-2 text-destructive hover:text-destructive"
            >
              <Trash2 className="h-4 w-4" />
              {t("shell.removeHotel")}
            </Button>
          </>
        ) : null}
      </div>
    </div>
  );

  return (
    <div
      className="min-h-dvh overflow-x-clip"
      style={{
        backgroundImage: "var(--gradient-paper)",
        backgroundAttachment: "fixed",
      }}
    >
      {/* Mobile/tablet top bar */}
      <header
        className="sticky top-0 z-30 flex items-center justify-between gap-3 border-b border-border/60 bg-card/80 backdrop-blur-md lg:hidden"
        style={{
          paddingTop: "max(0.75rem, var(--safe-top, env(safe-area-inset-top)))",
          paddingBottom: "0.75rem",
          paddingLeft: "max(1rem, var(--safe-left, env(safe-area-inset-left)))",
          paddingRight: "max(1rem, var(--safe-right, env(safe-area-inset-right)))",
        }}
      >
        <Link to="/" className="flex min-w-0 items-center gap-2">
          <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-brand text-primary-foreground">
            <Sun className="h-3.5 w-3.5" />
          </div>
          <div className="min-w-0">
            <div className="truncate font-serif text-base font-semibold leading-tight text-brand">
              {t("shell.brand")}
            </div>
            <div className="truncate text-[9px] uppercase tracking-[0.18em] text-muted-foreground">
              {isAllHotels ? t("shell.allHotels") : hotel?.hotel_name ?? ""}
            </div>
          </div>
        </Link>
        <div className="flex shrink-0 items-center gap-1">
          <Button
            size="icon"
            variant="ghost"
            onClick={onRefresh}
            disabled={isLoading || isAllHotels || !hotel}
            aria-label="Refresh briefing"
            className="h-9 w-9"
          >
            {isLoading ? (
              <Loader2 className="h-4 w-4 animate-spin" />
            ) : (
              <RefreshCw className="h-4 w-4" />
            )}
          </Button>
          {/* CreditsBadge hidden — AI usage is unmetered for hoteliers */}
          <UserMenu />
          <Button
            size="icon"
            variant="ghost"
            onClick={() => setDrawerOpen(true)}
            aria-label="Open menu"
            className="h-9 w-9"
          >
            <Menu className="h-5 w-5" />
          </Button>
        </div>
      </header>

      {/* Desktop top-right account menu */}
      <div className="pointer-events-none fixed right-6 top-6 z-30 hidden lg:block">
        <div className="pointer-events-auto flex items-center gap-2 rounded-full bg-card/80 p-1 pl-2 shadow-[var(--shadow-elegant)] backdrop-blur-md">
          {/* CreditsBadge hidden — AI usage is unmetered for hoteliers */}
          <UserMenu />
        </div>
      </div>

      <div
        className="container mx-auto flex min-h-dvh flex-col gap-6 pt-4 sm:pt-6 lg:flex-row lg:pb-8 lg:pt-8"
        style={{
          paddingLeft: "max(1rem, var(--safe-left, env(safe-area-inset-left)))",
          paddingRight: "max(1rem, var(--safe-right, env(safe-area-inset-right)))",
          paddingBottom: "calc(6rem + var(--safe-bottom, env(safe-area-inset-bottom)))",
        }}
      >
        {/* Desktop sidebar */}
        <aside className="hidden lg:sticky lg:top-8 lg:block lg:h-[calc(100dvh-4rem)] lg:w-64 lg:shrink-0">
          {sidebar}
        </aside>

        {/* Main content */}
        <main className="min-w-0 flex-1">{children}</main>
      </div>

      {/* Mobile bottom tab bar */}
      <nav
        className="fixed inset-x-0 bottom-0 z-30 border-t border-border/60 bg-card/95 backdrop-blur-md lg:hidden"
        style={{
          paddingBottom: "var(--safe-bottom, env(safe-area-inset-bottom))",
          paddingLeft: "var(--safe-left, env(safe-area-inset-left))",
          paddingRight: "var(--safe-right, env(safe-area-inset-right))",
        }}
      >
        <div className="mx-auto grid max-w-md grid-cols-6">
          {NAV_LIVE.map((item) => {
            const active = isActive(item.to);
            const Icon = item.icon;
            return (
              <Link
                key={item.to}
                to={item.to}
                className={`flex min-w-0 flex-col items-center justify-center gap-0.5 px-0.5 py-2 text-[9px] font-medium transition-colors sm:text-[10px] ${
                  active ? "text-brand" : "text-muted-foreground hover:text-foreground"
                }`}
              >
                <Icon className={`h-4 w-4 sm:h-5 sm:w-5 ${active ? "text-brand" : ""}`} />
                <span className="w-full truncate text-center leading-tight">{item.label}</span>
              </Link>
            );
          })}
        </div>
      </nav>

      {/* Mobile drawer */}
      {drawerOpen ? (
        <div className="fixed inset-0 z-50 lg:hidden" role="dialog" aria-modal="true">
          <div
            className="absolute inset-0 bg-foreground/40 backdrop-blur-sm"
            onClick={() => setDrawerOpen(false)}
          />
          <div
            className="absolute right-0 top-0 flex h-dvh w-[min(20rem,90vw)] flex-col bg-card shadow-2xl"
            style={{
              paddingTop: "var(--safe-top, env(safe-area-inset-top))",
              paddingBottom: "var(--safe-bottom, env(safe-area-inset-bottom))",
              paddingRight: "var(--safe-right, env(safe-area-inset-right))",
            }}
          >
            <div className="flex items-center justify-between border-b px-4 py-3">
              <span className="font-serif text-base font-semibold text-brand">{t("shell.menu")}</span>
              <Button
                size="icon"
                variant="ghost"
                onClick={() => setDrawerOpen(false)}
                aria-label="Close menu"
                className="h-8 w-8"
              >
                <X className="h-4 w-4" />
              </Button>
            </div>
            <div className="flex-1 overflow-y-auto">{sidebar}</div>
          </div>
        </div>
      ) : null}

      <DeleteAccountDialog open={deleteOpen} onOpenChange={setDeleteOpen} />
      <RemoveHotelDialog
        open={removeOpen}
        onOpenChange={setRemoveOpen}
        hotel={hotel}
      />
    </div>
  );
}

function DeleteAccountDialog({
  open,
  onOpenChange,
}: {
  open: boolean;
  onOpenChange: (v: boolean) => void;
}) {
  const t = useT();
  const navigate = useNavigate();
  const { signOut } = useAuth();
  const [confirm, setConfirm] = useState("");
  const [busy, setBusy] = useState(false);

  async function handleDelete() {
    setBusy(true);
    try {
      const { error } = await supabase.rpc("delete_my_account");
      if (error) throw error;
      toast.success("Account deleted");
      await signOut();
      navigate({ to: "/login" });
    } catch (err) {
      toast.error("Couldn't delete account", { description: (err as Error).message });
    } finally {
      setBusy(false);
      onOpenChange(false);
      setConfirm("");
    }
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle className="text-destructive">{t("delete.title")}</DialogTitle>
          <DialogDescription>{t("delete.body")}</DialogDescription>
        </DialogHeader>
        <div className="grid gap-2">
          <label className="text-xs font-medium text-muted-foreground">
            {t("delete.confirm")}
          </label>
          <Input
            value={confirm}
            onChange={(e) => setConfirm(e.target.value)}
            placeholder="DELETE"
            autoComplete="off"
          />
        </div>
        <DialogFooter>
          <Button variant="ghost" onClick={() => onOpenChange(false)} disabled={busy}>
            {t("delete.cancel")}
          </Button>
          <Button
            variant="destructive"
            onClick={handleDelete}
            disabled={busy || confirm !== "DELETE"}
            className="gap-2"
          >
            {busy ? <Loader2 className="h-4 w-4 animate-spin" /> : <Trash2 className="h-4 w-4" />}
            {t("delete.cta")}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

function RemoveHotelDialog({
  open,
  onOpenChange,
  hotel,
}: {
  open: boolean;
  onOpenChange: (v: boolean) => void;
  hotel: Hotel | null;
}) {
  const t = useT();
  const { selectHotel, refetch } = useHotels();
  const [confirm, setConfirm] = useState("");
  const [busy, setBusy] = useState(false);
  const expected = (hotel?.hotel_name ?? "").trim();

  async function handleRemove() {
    if (!hotel) return;
    setBusy(true);
    try {
      const { error } = await supabase
        .from("hotels")
        .delete()
        .eq("id", hotel.id);
      if (error) throw error;
      toast.success("Hotel removed");
      selectHotel(null);
      refetch();
      onOpenChange(false);
      setConfirm("");
    } catch (err) {
      toast.error("Couldn't remove", { description: (err as Error).message });
    } finally {
      setBusy(false);
    }
  }

  return (
    <Dialog open={open} onOpenChange={(v) => { if (!busy) { onOpenChange(v); if (!v) setConfirm(""); } }}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle className="text-destructive">{t("remove.title")}</DialogTitle>
          <DialogDescription>
            {t("remove.body")}
            {hotel ? (
              <span className="mt-2 block font-medium text-foreground">{hotel.hotel_name}</span>
            ) : null}
          </DialogDescription>
        </DialogHeader>
        <div className="grid gap-2">
          <label className="text-xs font-medium text-muted-foreground">
            {t("remove.confirm")}
          </label>
          <Input
            value={confirm}
            onChange={(e) => setConfirm(e.target.value)}
            placeholder={expected}
            autoComplete="off"
          />
        </div>
        <DialogFooter>
          <Button variant="ghost" onClick={() => onOpenChange(false)} disabled={busy}>
            {t("remove.cancel")}
          </Button>
          <Button
            variant="destructive"
            onClick={handleRemove}
            disabled={busy || !expected || confirm.trim() !== expected}
            className="gap-2"
          >
            {busy ? <Loader2 className="h-4 w-4 animate-spin" /> : <Trash2 className="h-4 w-4" />}
            {t("remove.cta")}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
