"use client";

import { usePathname, useRouter } from "next/navigation";
import { useEffect, useMemo, useRef, useState } from "react";

import { PixelAvatar } from "@/components/pixel-avatar";
import { useUiPreferences } from "@/components/ui-preference-provider";
import { XpBar } from "@/components/xp-bar";
import { apiFetch } from "@/lib/api";
import { clearToken, readToken } from "@/lib/auth";
import type { ThemeId } from "@/themes/types";

type NavLink = {
  label: string;
  href: string;
};

type NavGroup = {
  key: string;
  label: string;
  links: NavLink[];
};

type MeProfile = {
  id?: number;
  username?: string;
};

function buildNavGroups(t: (key: string) => string, isAdmin: boolean): NavGroup[] {
  const groups: NavGroup[] = [
    {
      key: "learn",
      label: t("nav.group.learn"),
      links: [
        { label: t("nav.link.home"), href: "/" },
        { label: t("nav.link.problems"), href: "/problems" },
        { label: t("nav.link.submissions"), href: "/submissions" },
        { label: t("nav.link.wrong_book"), href: "/wrong-book" },
        { label: t("nav.link.kb"), href: "/kb" },
        { label: t("nav.link.run"), href: "/run" },
      ],
    },
    {
      key: "contest",
      label: t("nav.group.contest"),
      links: [
        { label: t("nav.link.contests"), href: "/contests" },
        { label: t("nav.link.leaderboard"), href: "/leaderboard" },
      ],
    },
    {
      key: "account",
      label: t("nav.group.account"),
      links: [
        { label: t("nav.link.auth"), href: "/auth" },
        { label: t("nav.link.me"), href: "/me" },
      ],
    },
  ];

  if (isAdmin) {
    groups.splice(2, 0, {
      key: "system",
      label: t("nav.group.system"),
      links: [
        { label: t("nav.link.imports"), href: "/imports" },
        { label: t("nav.link.backend_logs"), href: "/backend-logs" },
        { label: t("nav.link.admin_users"), href: "/admin-users" },
        { label: t("nav.link.admin_redeem"), href: "/admin-redeem" },
        { label: t("nav.link.api_docs"), href: "/api-docs" },
      ],
    });
  }

  return groups;
}

function isActivePath(pathname: string, href: string): boolean {
  if (pathname === href) return true;
  if (href === "/") return pathname === "/";
  return pathname.startsWith(`${href}/`);
}

function resolveActiveGroup(pathname: string, groups: NavGroup[]): string {
  for (const group of groups) {
    for (const item of group.links) {
      if (isActivePath(pathname, item.href)) return group.key;
    }
  }
  return groups[0]?.key ?? "learn";
}

function resolveActiveLink(pathname: string, group: NavGroup): string {
  for (const item of group.links) {
    if (isActivePath(pathname, item.href)) return item.href;
  }
  return group.links[0]?.href ?? "/";
}

export function AppNav() {
  const pathname = usePathname();
  const router = useRouter();
  const { theme, setTheme, language, setLanguage, themes, t } = useUiPreferences();
  const directHttpAccessUrl =
    process.env.NEXT_PUBLIC_HTTP_ENTRY_URL?.trim() || "http://8.211.173.24:7888/";

  const [hasToken, setHasToken] = useState<boolean>(() => Boolean(readToken()));
  const [isAdmin, setIsAdmin] = useState(false);
  const [meProfile, setMeProfile] = useState<MeProfile | null>(null);
  const [menuOpen, setMenuOpen] = useState(false);
  const [desktopOpenGroup, setDesktopOpenGroup] = useState<string | null>(null);
  const desktopMenuRef = useRef<HTMLDivElement | null>(null);
  const navGroups = useMemo(() => buildNavGroups(t, isAdmin), [isAdmin, t]);
  const activeGroup = resolveActiveGroup(pathname, navGroups);
  const usePopupSecondary = theme === "default" || theme === "minecraft";

  useEffect(() => {
    let canceled = false;
    const refresh = async () => {
      const token = readToken();
      if (canceled) return;
      setHasToken(Boolean(token));
      if (!token) {
        setIsAdmin(false);
        setMeProfile(null);
        return;
      }
      try {
        const me = await apiFetch<MeProfile>("/api/v1/me", {}, token);
        if (!canceled) {
          setIsAdmin((me?.username ?? "") === "admin");
          setMeProfile(me ?? null);
        }
      } catch {
        if (!canceled) {
          setIsAdmin(false);
          setMeProfile(null);
        }
      }
    };
    const onRefresh = () => {
      void refresh();
    };
    void refresh();
    window.addEventListener("storage", onRefresh);
    window.addEventListener("focus", onRefresh);
    return () => {
      canceled = true;
      window.removeEventListener("storage", onRefresh);
      window.removeEventListener("focus", onRefresh);
    };
  }, [pathname]);

  useEffect(() => {
    if (!usePopupSecondary || !desktopOpenGroup) return;
    const onMouseDown = (event: MouseEvent) => {
      const target = event.target as Node | null;
      if (!target) return;
      if (desktopMenuRef.current?.contains(target)) return;
      setDesktopOpenGroup(null);
    };
    window.addEventListener("mousedown", onMouseDown);
    return () => window.removeEventListener("mousedown", onMouseDown);
  }, [desktopOpenGroup, usePopupSecondary]);

  const currentGroup = navGroups.find((g) => g.key === activeGroup) ?? navGroups[0];
  const avatarSeed = meProfile
    ? `${meProfile.username ?? "user"}-${meProfile.id ?? ""}`
    : "guest";
  const handleLogout = () => {
    clearToken();
    setHasToken(false);
    setIsAdmin(false);
    setMeProfile(null);
    setDesktopOpenGroup(null);
  };

  return (
    <header className="print-hidden border-b bg-[color:var(--surface)]/95 backdrop-blur supports-[backdrop-filter]:bg-[color:var(--surface)]/85">
      <div className="mx-auto max-w-6xl px-3 py-3 max-[390px]:px-2 max-[390px]:py-2 sm:px-4">
        <div className="flex items-center justify-between md:hidden">
          <span className="text-sm font-medium text-zinc-700">{t("nav.menu")}</span>
          <button
            type="button"
            className="rounded-md border px-3 py-1 text-sm hover:bg-zinc-100 max-[390px]:px-2 max-[390px]:text-xs"
            onClick={() => setMenuOpen((v) => !v)}
            aria-expanded={menuOpen}
            aria-controls="main-nav-links"
          >
            {menuOpen ? t("nav.collapse") : t("nav.expand")}
          </button>
        </div>

        <div id="main-nav-links" className={`${menuOpen ? "mt-3 block" : "hidden"} md:mt-0 md:block`}>
          <div className="space-y-3">
            {usePopupSecondary ? (
              <div ref={desktopMenuRef} className="hidden flex-wrap items-center gap-2 md:flex">
                {navGroups.map((group) => {
                  const active = activeGroup === group.key;
                  const opened = desktopOpenGroup === group.key;
                  return (
                    <div key={group.key} className="relative">
                      <button
                        type="button"
                        className={`rounded-md border px-3 py-1 text-sm ${active ? "border-zinc-900 bg-zinc-900 text-white" : "hover:bg-zinc-100"
                          }`}
                        aria-expanded={opened}
                        onClick={() =>
                          setDesktopOpenGroup((prev) => (prev === group.key ? null : group.key))
                        }
                      >
                        {group.label}
                      </button>
                      {opened && (
                        <div
                          className={`absolute left-0 top-full z-50 mt-2 rounded-md border bg-[color:var(--surface)] p-1 shadow-lg ${group.key === "account" ? "min-w-[18rem]" : "min-w-[11rem]"
                            }`}
                        >
                          {group.links.map((item) => {
                            const linkActive = isActivePath(pathname, item.href);
                            return (
                              <button
                                key={item.href}
                                type="button"
                                className={`block w-full rounded px-3 py-1.5 text-left text-sm ${linkActive ? "bg-zinc-900 text-white" : "hover:bg-zinc-100"
                                  }`}
                                onClick={() => {
                                  setDesktopOpenGroup(null);
                                  router.push(item.href);
                                }}
                              >
                                {item.label}
                              </button>
                            );
                          })}
                          {group.key === "account" && (
                            <div className="mt-2 space-y-2 border-t border-zinc-200 px-2 pt-2">
                              <label className="block text-xs">
                                <span className="text-zinc-500">{t("prefs.theme")}</span>
                                <select
                                  className="mt-1 w-full rounded-md border px-2 py-1 text-xs"
                                  value={theme}
                                  onChange={(e) => setTheme(e.target.value as ThemeId)}
                                >
                                  {themes.map((item) => (
                                    <option key={item.id} value={item.id}>
                                      {item.labels[language]}
                                    </option>
                                  ))}
                                </select>
                              </label>
                              <label className="block text-xs">
                                <span className="text-zinc-500">{t("prefs.language")}</span>
                                <select
                                  className="mt-1 w-full rounded-md border px-2 py-1 text-xs"
                                  value={language}
                                  onChange={(e) => setLanguage(e.target.value === "zh" ? "zh" : "en")}
                                >
                                  <option value="en">{t("prefs.lang.en")}</option>
                                  <option value="zh">{t("prefs.lang.zh")}</option>
                                </select>
                              </label>
                              <div className="flex items-center justify-between gap-2 rounded-md border border-zinc-200 px-2 py-1.5">
                                <div className="flex min-w-0 items-center gap-2">
                                  <span className={hasToken ? "text-emerald-700" : "text-zinc-500"}>
                                    {hasToken ? t("nav.logged_in") : t("nav.logged_out")}
                                  </span>
                                  {hasToken && (
                                    <>
                                      <PixelAvatar
                                        seed={avatarSeed}
                                        size={20}
                                        className="border-zinc-700"
                                        alt={meProfile?.username ? `${meProfile.username} avatar` : "avatar"}
                                      />
                                      {meProfile?.username && (
                                        <span className="truncate text-xs text-zinc-500">{meProfile.username}</span>
                                      )}
                                    </>
                                  )}
                                </div>
                                {hasToken && (
                                  <button
                                    type="button"
                                    className="rounded-md border px-2 py-1 text-xs hover:bg-zinc-100"
                                    onClick={handleLogout}
                                  >
                                    {t("nav.logout")}
                                  </button>
                                )}
                              </div>
                            </div>
                          )}
                        </div>
                      )}
                    </div>
                  );
                })}
              </div>
            ) : (
              <>
                <div className="hidden flex-wrap items-center gap-2 md:flex">
                  {navGroups.map((group) => {
                    const active = activeGroup === group.key;
                    return (
                      <button
                        key={group.key}
                        type="button"
                        className={`rounded-md border px-3 py-1 text-sm ${active ? "border-zinc-900 bg-zinc-900 text-white" : "hover:bg-zinc-100"
                          }`}
                        onClick={() => router.push(group.links[0]?.href ?? "/")}
                      >
                        {group.label}
                      </button>
                    );
                  })}
                </div>

                <div className="hidden items-center gap-2 md:flex">
                  <span className="text-xs text-zinc-500">{t("nav.secondary_menu")}</span>
                  <select
                    className="min-w-[220px] rounded-md border px-3 py-1 text-sm"
                    value={resolveActiveLink(pathname, currentGroup)}
                    onChange={(e) => router.push(e.target.value)}
                  >
                    {currentGroup.links.map((item) => (
                      <option key={item.href} value={item.href}>
                        {item.label}
                      </option>
                    ))}
                  </select>
                </div>
              </>
            )}

            <div className="space-y-3 md:hidden">
              {navGroups.map((group) => (
                <section key={group.key} className="rounded-lg border p-2">
                  <h3 className="text-xs font-semibold text-zinc-600">{group.label}</h3>
                  <select
                    className="mt-2 w-full rounded-md border px-3 py-1 text-xs"
                    value={resolveActiveLink(pathname, group)}
                    onChange={(e) => {
                      setMenuOpen(false);
                      router.push(e.target.value);
                    }}
                  >
                    {group.links.map((item) => (
                      <option key={item.href} value={item.href}>
                        {item.label}
                      </option>
                    ))}
                  </select>
                </section>
              ))}
            </div>
          </div>
        </div>

        <div className={`mt-2 flex flex-wrap items-center justify-end gap-2 text-xs sm:text-sm ${usePopupSecondary ? "md:hidden" : ""}`}>
          <label className="inline-flex items-center gap-1">
            <span className="text-zinc-500">{t("prefs.theme")}</span>
            <select
              className="rounded-md border px-2 py-1 text-xs sm:text-sm"
              value={theme}
              onChange={(e) => {
                setDesktopOpenGroup(null);
                setTheme(e.target.value as ThemeId);
              }}
            >
              {themes.map((item) => (
                <option key={item.id} value={item.id}>
                  {item.labels[language]}
                </option>
              ))}
            </select>
          </label>
          <label className="inline-flex items-center gap-1">
            <span className="text-zinc-500">{t("prefs.language")}</span>
            <select
              className="rounded-md border px-2 py-1 text-xs sm:text-sm"
              value={language}
              onChange={(e) => setLanguage(e.target.value === "zh" ? "zh" : "en")}
            >
              <option value="en">{t("prefs.lang.en")}</option>
              <option value="zh">{t("prefs.lang.zh")}</option>
            </select>
          </label>
          <a
            href={directHttpAccessUrl}
            target="_blank"
            rel="noreferrer"
            className="rounded-md border px-2 py-1 text-xs hover:bg-zinc-100 sm:text-sm"
            title={directHttpAccessUrl}
          >
            {t("nav.link.http_ip_port")}
          </a>
          <span className={hasToken ? "text-emerald-700" : "text-zinc-500"}>
            {hasToken ? t("nav.logged_in") : t("nav.logged_out")}
          </span>
          {hasToken && (
            <>
              {theme === "minecraft" && (
                <div className="hidden md:block w-32 mr-2">
                  <XpBar level={5} currentXp={750} nextLevelXp={1000} />
                </div>
              )}
              <PixelAvatar
                seed={avatarSeed}
                size={24}
                className="border-zinc-700"
                alt={meProfile?.username ? `${meProfile.username} avatar` : "avatar"}
              />
            </>
          )}
          {hasToken && (
            <button
              onClick={handleLogout}
              className="rounded-md border px-3 py-1 hover:bg-zinc-100"
            >
              {t("nav.logout")}
            </button>
          )}
        </div>
      </div>
    </header>
  );
}
