import { useEffect, useRef, useState, useSyncExternalStore } from "react";
import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next";
import { useQuery } from "@tanstack/react-query";
import {
  Activity,
  BarChart3,
  Bell,
  ChevronLeft,
  ChevronRight,
  Home,
  Info,
  ListVideo,
  LogOut,
  Settings,
  Shield,
  SlidersHorizontal,
  Tv,
  UserPlus,
} from "lucide-react";
import { api, type Me } from "../lib/api";
import { useLiveQuery } from "../lib/useLiveQuery";
import { getUnreadCount, subscribe } from "../lib/notifications";
import type { Page } from "../lib/urlState";
import { type LangCode } from "../i18n";
import AvatarImg from "./Avatar";
import LanguageSwitcher from "./LanguageSwitcher";

// Primary app navigation: a collapsible left rail with icon+label entries (Design C). The
// modules used to hide under the avatar dropdown; they now live here. Collapsed, it becomes
// a thin icon-only rail. Account actions sit at the bottom in a popover.
export default function NavSidebar({
  me,
  page,
  setPage,
  onOpenAbout,
  onChangeLanguage,
  language,
}: {
  me: Me;
  page: Page;
  setPage: (p: Page) => void;
  onOpenAbout: () => void;
  onChangeLanguage: (code: LangCode) => void;
  language: LangCode;
}) {
  const { t } = useTranslation();
  const [collapsed, setCollapsed] = useState<boolean>(
    () => localStorage.getItem("siftlode.navCollapsed") === "1"
  );
  const [acctOpen, setAcctOpen] = useState(false);
  const acctBtnRef = useRef<HTMLButtonElement | null>(null);
  const acctPanelRef = useRef<HTMLDivElement | null>(null);
  // Popover position (fixed, viewport coords). It's portaled to <body> so it escapes the
  // nav's backdrop-filter, which would otherwise trap fixed positioning + stacking and let
  // clicks fall through to the controls behind it.
  const [acctPos, setAcctPos] = useState<{ left: number; bottom: number }>({ left: 0, bottom: 0 });

  function toggleAccount() {
    if (!acctOpen) {
      const r = acctBtnRef.current?.getBoundingClientRect();
      if (r) setAcctPos({ left: r.right + 8, bottom: window.innerHeight - r.bottom });
    }
    setAcctOpen((o) => !o);
  }

  // Dismiss on outside click / Escape via document listeners — NOT a full-screen backdrop
  // div, which (sitting between the popover and the page) would break the popover's
  // backdrop-filter and make it look solid.
  useEffect(() => {
    if (!acctOpen) return;
    function onDoc(e: MouseEvent) {
      const t = e.target as Node;
      if (acctPanelRef.current?.contains(t) || acctBtnRef.current?.contains(t)) return;
      setAcctOpen(false);
    }
    function onKey(e: KeyboardEvent) {
      if (e.key === "Escape") setAcctOpen(false);
    }
    document.addEventListener("mousedown", onDoc);
    document.addEventListener("keydown", onKey);
    return () => {
      document.removeEventListener("mousedown", onDoc);
      document.removeEventListener("keydown", onKey);
    };
  }, [acctOpen]);

  function toggleCollapsed() {
    setCollapsed((c) => {
      const next = !c;
      localStorage.setItem("siftlode.navCollapsed", next ? "1" : "0");
      return next;
    });
  }

  async function logout() {
    await fetch("/auth/logout", { method: "POST", credentials: "include" });
    location.reload();
  }

  // Accounts that have signed in on this browser (loaded only while the popover is open).
  const accountsQuery = useQuery({
    queryKey: ["accounts"],
    queryFn: api.accounts,
    enabled: acctOpen,
  });
  const otherAccounts = (accountsQuery.data ?? []).filter((a) => !a.active);

  async function switchTo(id: number) {
    try {
      await api.switchAccount(id);
      location.reload(); // cleanest way to reload all per-user state for the new account
    } catch {
      /* a revoked/removed account — leave the popover open */
    }
  }

  // Durable, server-backed unread count for the inbox badge. Polled live (pauses when the
  // tab is hidden); coexists with the client-side transient bell at the bottom of the rail.
  const unreadQuery = useLiveQuery(
    ["notif-unread"],
    api.notificationUnreadCount,
    { intervalMs: 30000 }
  );
  // One indicator for both layers: durable server notifications + the client-side transient
  // events (the former separate bell is now folded into the inbox page).
  const clientUnread = useSyncExternalStore(subscribe, getUnreadCount, getUnreadCount);
  const unread = (unreadQuery.data?.count ?? 0) + clientUnread;

  type NavItem = { page: Page; icon: typeof Home; label: string; badge?: number };
  // User-facing content modules vs. admin/system modules, separated by a divider in the rail.
  const userItems: NavItem[] = [
    { page: "feed", icon: Home, label: t("header.account.feed") },
    { page: "channels", icon: Tv, label: t("header.account.channels") },
    { page: "playlists", icon: ListVideo, label: t("header.account.playlists") },
    { page: "notifications", icon: Bell, label: t("inbox.navLabel"), badge: unread },
    // Per-user sync status + your own API usage (admins get an extra system-wide tab inside).
    { page: "stats", icon: BarChart3, label: t("header.account.stats") },
  ];
  const systemItems: NavItem[] =
    me.role === "admin"
      ? [
          { page: "scheduler", icon: Activity, label: t("header.account.scheduler") },
          { page: "config", icon: SlidersHorizontal, label: t("header.account.config") },
        ]
      : [];

  const rowBase =
    "w-full flex items-center gap-3 rounded-lg px-2.5 py-2 text-sm transition";
  const name = me.display_name ?? me.email.split("@")[0];

  const renderItem = ({ page: p, icon: Icon, label, badge }: NavItem) => {
    const active = page === p;
    // On the active row the background is the accent colour, so a same-accent badge would be
    // red-on-red. Invert it there (light pill, accent-coloured number) for clean contrast.
    const badgeColor = active ? "bg-accent-fg text-accent" : "bg-accent text-accent-fg";
    const show = !!badge && badge > 0;
    return (
      <button
        key={p}
        onClick={() => setPage(p)}
        title={collapsed ? label : undefined}
        aria-current={active ? "page" : undefined}
        className={`${rowBase} ${collapsed ? "justify-center px-0" : ""} relative ${
          active ? "bg-accent text-accent-fg" : "text-muted hover:text-fg hover:bg-card"
        }`}
      >
        <span className="relative shrink-0">
          <Icon className="w-[18px] h-[18px]" />
          {/* Collapsed rail: a numeric badge centred on a circle at the icon corner; the ring
              matches the row background so it reads cleanly whether the row is active or not. */}
          {show && collapsed && (
            <span
              className={`absolute -top-2 -right-2 min-w-[16px] h-4 px-1 rounded-full text-[10px] font-bold leading-none grid place-items-center ring-2 ${badgeColor} ${
                active ? "ring-accent" : "ring-bg"
              }`}
            >
              {badge > 9 ? "9+" : badge}
            </span>
          )}
        </span>
        {!collapsed && <span className="truncate">{label}</span>}
        {show && !collapsed && (
          <span
            className={`ml-auto min-w-[18px] h-[18px] px-1.5 rounded-full text-[11px] font-semibold leading-none inline-flex items-center justify-center tabular-nums ${badgeColor}`}
          >
            {badge > 99 ? "99+" : badge}
          </span>
        )}
      </button>
    );
  };

  return (
    <nav
      className={`glass relative shrink-0 border-r border-border flex flex-col py-3 transition-[width] ${
        collapsed ? "w-[56px] px-2" : "w-52 px-3"
      }`}
      aria-label={t("nav.primary")}
    >
      <div className={`flex items-center mb-3 ${collapsed ? "justify-center" : "justify-between"}`}>
        {!collapsed && (
          <button
            onClick={() => setPage("feed")}
            className="text-lg font-bold tracking-tight select-none"
            title={t("header.feed")}
          >
            Sift<span className="text-accent">lode</span>
          </button>
        )}
        <button
          onClick={toggleCollapsed}
          title={collapsed ? t("nav.expand") : t("nav.collapse")}
          aria-label={collapsed ? t("nav.expand") : t("nav.collapse")}
          className="p-1 rounded-md text-muted hover:text-fg hover:bg-card transition"
        >
          {collapsed ? (
            <ChevronRight className="w-4 h-4" />
          ) : (
            <ChevronLeft className="w-4 h-4" />
          )}
        </button>
      </div>

      <div className="flex-1 min-h-0 overflow-y-auto flex flex-col gap-1">
        {userItems.map(renderItem)}
        {systemItems.length > 0 && (
          <div className="my-1.5 border-t border-border/70" />
        )}
        {systemItems.map(renderItem)}
      </div>

      <div className="mt-2 pt-2 border-t border-border flex flex-col gap-1">
        <div
          className={`flex items-center justify-center gap-2 pb-2 mb-1 border-b border-border ${
            collapsed ? "flex-col" : "flex-row"
          }`}
        >
          <LanguageSwitcher variant="rail" value={language} onChange={onChangeLanguage} />
          <button
            onClick={onOpenAbout}
            title={t("header.account.about")}
            aria-label={t("header.account.about")}
            className="p-2 rounded-lg text-muted hover:text-fg hover:bg-card transition"
          >
            <Info className="w-5 h-5" />
          </button>
        </div>
        <button
          onClick={() => setPage("settings")}
          title={collapsed ? t("header.account.settings") : undefined}
          aria-current={page === "settings" ? "page" : undefined}
          className={`${rowBase} ${collapsed ? "justify-center px-0" : ""} ${
            page === "settings"
              ? "bg-accent text-accent-fg"
              : "text-muted hover:text-fg hover:bg-card"
          }`}
        >
          <Settings className="w-[18px] h-[18px] shrink-0" />
          {!collapsed && <span className="truncate">{t("header.account.settings")}</span>}
        </button>

        <div className="relative">
          <button
            ref={acctBtnRef}
            onClick={toggleAccount}
            title={collapsed ? name : undefined}
            className={`${rowBase} ${collapsed ? "justify-center px-0" : ""} text-muted hover:text-fg hover:bg-card`}
          >
            <AvatarImg
              src={me.avatar_url}
              fallback={name}
              className="w-[22px] h-[22px] rounded-full text-[10px] shrink-0"
            />
            {!collapsed && <span className="truncate flex-1 text-left">{name}</span>}
          </button>

          {acctOpen &&
            createPortal(
              <div
                ref={acctPanelRef}
                style={{ position: "fixed", left: acctPos.left, bottom: acctPos.bottom }}
                className="glass w-60 rounded-xl p-3 z-50 animate-[popIn_0.16s_ease]"
              >
                <div className="flex items-center gap-3 pb-3 border-b border-border">
                  <AvatarImg
                    src={me.avatar_url}
                    fallback={name}
                    className="w-10 h-10 rounded-full text-sm shrink-0"
                  />
                  <div className="min-w-0">
                    <div className="text-sm font-semibold truncate">{name}</div>
                    <div className="text-xs text-muted truncate">{me.email}</div>
                  </div>
                </div>
                {me.role === "admin" && (
                  <div className="flex items-center gap-1.5 mt-2 text-[11px] font-medium text-accent">
                    <Shield className="w-3.5 h-3.5" />
                    {t("header.account.admin")}
                  </div>
                )}
                {otherAccounts.length > 0 && (
                  <div className="mt-2 pt-2 border-t border-border flex flex-col gap-0.5">
                    {otherAccounts.map((a) => (
                      <button
                        key={a.id}
                        onClick={() => switchTo(a.id)}
                        title={t("header.account.switchTo", { name: a.display_name ?? a.email })}
                        className="w-full flex items-center gap-2.5 px-2 py-1.5 rounded-lg hover:bg-card transition"
                      >
                        <AvatarImg
                          src={a.avatar_url}
                          fallback={a.display_name ?? a.email}
                          className="w-6 h-6 rounded-full text-[10px] shrink-0"
                        />
                        <span className="min-w-0 text-left">
                          <span className="block text-[13px] text-fg truncate">
                            {a.display_name ?? a.email.split("@")[0]}
                          </span>
                          <span className="block text-[11px] text-muted truncate">{a.email}</span>
                        </span>
                      </button>
                    ))}
                  </div>
                )}
                <div className="mt-2 pt-2 border-t border-border flex flex-col">
                  <button
                    onClick={() => {
                      window.location.href = "/auth/login";
                    }}
                    className="w-full flex items-center gap-2 text-sm px-2 py-2 rounded-lg text-muted hover:text-fg hover:bg-card transition"
                  >
                    <UserPlus className="w-4 h-4" />
                    {t("header.account.addAccount")}
                  </button>
                  <button
                    onClick={logout}
                    className="w-full flex items-center gap-2 text-sm px-2 py-2 rounded-lg text-muted hover:text-fg hover:bg-card transition"
                  >
                    <LogOut className="w-4 h-4" />
                    {t("header.account.signOut")}
                  </button>
                </div>
              </div>,
              document.body
            )}
        </div>
      </div>
    </nav>
  );
}
