import { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import type { PageId } from '../../lib/urlState';
import type { AuthUser } from '../../App';
import { ThemeToggle } from './ThemeToggle';
import { ChangePasswordDialog } from '../admin/LocalUserDialogs';

interface TopBarProps {
  currentPage: PageId;
  onNavigate: (page: PageId) => void;
  isAdmin?: boolean;
  authEnabled?: boolean;
  user?: AuthUser | null;
  appName?: string;
  logoUrl?: string | null;
  onOpenDrawer: () => void;
  hamburgerButtonRef?: React.RefObject<HTMLButtonElement>;
  navDrawerOpen?: boolean;
  onOpenCommandK?: () => void;
  /** Reports the measured compact state up so App can drive the nav drawer /
   *  edge-swipe. Called whenever the collapse decision flips. */
  onCompactChange?: (compact: boolean) => void;
}

// labelKey resolves against the `layout` i18n namespace at render time (module
// scope can't call hooks). All consumers translate: TopBar, NavDrawer, App.tsx.
export const NAV_ITEMS: Array<{ id: PageId; labelKey: string; adminOnly: boolean; requiresAuth: boolean }> = [
  { id: 'tasks', labelKey: 'nav.tasks', adminOnly: false, requiresAuth: false },
  { id: 'schedules', labelKey: 'nav.schedules', adminOnly: false, requiresAuth: false },
  { id: 'pieces', labelKey: 'nav.pieces', adminOnly: false, requiresAuth: false },
  { id: 'captcha', labelKey: 'nav.captcha', adminOnly: true, requiresAuth: false },
  { id: 'usage', labelKey: 'nav.usage', adminOnly: false, requiresAuth: false },
  { id: 'settings', labelKey: 'nav.settings', adminOnly: false, requiresAuth: false },
  { id: 'users', labelKey: 'nav.users', adminOnly: true, requiresAuth: true },
  { id: 'help', labelKey: 'nav.help', adminOnly: false, requiresAuth: false },
  { id: 'userfolder', labelKey: 'nav.userfolder', adminOnly: false, requiresAuth: false },
];

/**
 * Decide whether the inline nav must collapse into the hamburger, from MEASURED
 * widths (not a width estimate). Collapse exactly when the nav's natural width
 * no longer fits the space left after the fixed left content (logo/name/version)
 * and the right-side controls. The buffer keeps a small gap so tabs never touch
 * the controls. Before anything is measured (zero widths) we assume it fits, so
 * the bar paints with tabs rather than flashing the hamburger.
 */
export function shouldCollapseNav(
  rowWidth: number,
  fixedWidth: number,
  navWidth: number,
  buffer = 40,
): boolean {
  if (rowWidth <= 0 || navWidth <= 0) return false;
  return navWidth > rowWidth - fixedWidth - buffer;
}

export function useViewportNarrow(threshold: number): boolean {
  const [narrow, setNarrow] = useState(() =>
    typeof window !== 'undefined' ? window.innerWidth < threshold : false,
  );
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const update = () => setNarrow(window.innerWidth < threshold);
    update();
    window.addEventListener('resize', update);
    return () => window.removeEventListener('resize', update);
  }, [threshold]);
  return narrow;
}

export function visibleNavItemsFor(isAdmin: boolean, authEnabled: boolean) {
  return NAV_ITEMS.filter(item => {
    if (item.adminOnly && !isAdmin) return false;
    if (item.requiresAuth && !authEnabled) return false;
    return true;
  });
}

export function TopBar({
  currentPage,
  onNavigate,
  isAdmin = true,
  authEnabled = false,
  user = null,
  appName = 'MAESTRO',
  logoUrl = null,
  onOpenDrawer,
  hamburgerButtonRef,
  navDrawerOpen = false,
  onOpenCommandK,
  onCompactChange,
}: TopBarProps) {
  const { t } = useTranslation('layout');
  const visibleNav = visibleNavItemsFor(isAdmin, authEnabled);
  const [showPwChange, setShowPwChange] = useState(false);

  // Collapse-to-hamburger decision from MEASURED widths, so it flips exactly
  // when the tabs stop fitting — no width estimate, no 2-line state.
  const rowRef = useRef<HTMLDivElement>(null);
  const leftFixedRef = useRef<HTMLDivElement>(null); // logo + appName + version (NOT the nav)
  const rightRef = useRef<HTMLDivElement>(null);     // right-side controls
  const navRulerRef = useRef<HTMLDivElement>(null);  // off-screen full-width nav, always present
  const [compactMode, setCompactMode] = useState(false);

  useLayoutEffect(() => {
    const row = rowRef.current;
    if (!row || typeof ResizeObserver === 'undefined') return;
    const measure = () => {
      const leftFixed = leftFixedRef.current?.offsetWidth ?? 0;
      const right = rightRef.current?.offsetWidth ?? 0;
      const navWidth = navRulerRef.current?.offsetWidth ?? 0;
      setCompactMode(shouldCollapseNav(row.clientWidth, leftFixed + right, navWidth));
    };
    const ro = new ResizeObserver(measure);
    ro.observe(row);
    // Observe the ruler + right group too: their widths change with language
    // (label lengths) and login state, which also moves the collapse point.
    if (navRulerRef.current) ro.observe(navRulerRef.current);
    if (rightRef.current) ro.observe(rightRef.current);
    measure();
    return () => ro.disconnect();
  }, [visibleNav.length, t]);

  useEffect(() => {
    onCompactChange?.(compactMode);
  }, [compactMode, onCompactChange]);

  return (
    <div
      className="flex-shrink-0 bg-canvas border-b border-hairline px-4 flex items-center"
      style={{
        paddingTop: 'env(safe-area-inset-top, 0px)',
        minHeight: 'calc(48px + env(safe-area-inset-top, 0px))',
      }}
    >
      <div ref={rowRef} className="relative flex items-center justify-between gap-3 flex-nowrap w-full py-1.5 min-w-0">
        {/* Off-screen full-width nav ruler. Always rendered (absolute, out of
            flow) so its width is measurable even while the visible nav is
            collapsed — that constant width is what keeps the collapse decision
            from oscillating. INVARIANT: this ruler must stay a width-SUPERSET
            of the real nav (same px/gap, every label font-semibold = the widest
            state). If it ever underestimates the real nav, the 2-line bug
            returns. Do NOT add per-item active/inactive weight here. */}
        <nav
          ref={navRulerRef}
          aria-hidden="true"
          className="absolute left-0 top-0 invisible pointer-events-none flex gap-5 ml-2"
        >
          {visibleNav.map(item => (
            <span key={item.id} className="px-0.5 text-xs font-semibold whitespace-nowrap">
              {t(item.labelKey)}
            </span>
          ))}
        </nav>

        <div className="flex items-center gap-4 min-w-0 self-stretch">
          {compactMode && (
            <button
              ref={hamburgerButtonRef}
              type="button"
              onClick={onOpenDrawer}
              aria-label={t('nav.openMenu')}
              aria-expanded={navDrawerOpen}
              aria-haspopup="dialog"
              aria-controls="nav-drawer"
              className="-ml-2 flex items-center justify-center w-11 h-11 rounded-md text-slate-700 hover:bg-surface focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-ring transition-colors"
            >
              <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden>
                <line x1="3" y1="6" x2="21" y2="6" />
                <line x1="3" y1="12" x2="21" y2="12" />
                <line x1="3" y1="18" x2="21" y2="18" />
              </svg>
            </button>
          )}
          {/* leftFixedRef must wrap ONLY logo/name/version — the hamburger is a
              sibling above, kept out of this measurement so toggling it doesn't
              change leftFixed width (which would oscillate the collapse). */}
          <div ref={leftFixedRef} className="flex items-center gap-4 flex-shrink-0">
            <img
              src={logoUrl ?? `${import.meta.env.BASE_URL}favicon.svg`}
              alt=""
              className="flex-shrink-0 h-[22px] w-auto max-w-[140px] object-contain"
            />
            <span className="text-xs font-semibold tracking-tight text-slate-900 hidden sm:inline">
              {appName}
            </span>
            <span className="text-[10px] font-mono text-slate-400 hidden sm:inline">
              v{__APP_VERSION__}
            </span>
          </div>

          {!compactMode && (
            <nav className="flex gap-5 items-stretch -mb-[13px] ml-2 flex-shrink-0" aria-label={t('nav.mainNav')}>
              {visibleNav.map(item => {
                const active = currentPage === item.id;
                return (
                  <button
                    key={item.id}
                    type="button"
                    onClick={() => onNavigate(item.id)}
                    aria-current={active ? 'page' : undefined}
                    className={`relative whitespace-nowrap px-0.5 pb-3 text-xs border-b-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-ring ${
                      active
                        ? 'font-semibold text-slate-900 border-accent'
                        : 'font-medium text-slate-500 border-transparent hover:text-slate-800'
                    }`}
                  >
                    {t(item.labelKey)}
                  </button>
                );
              })}
            </nav>
          )}
        </div>

        <div ref={rightRef} className="flex items-center gap-2 flex-shrink-0">
          {onOpenCommandK && (
            <button
              type="button"
              onClick={onOpenCommandK}
              aria-label={t('commandPalette.open')}
              title={t('commandPalette.title')}
              className="hidden sm:inline-flex items-center gap-1 px-2 h-7 rounded-md border border-hairline text-2xs text-slate-500 hover:text-slate-800 hover:bg-surface transition-colors"
            >
              <span aria-hidden>⌘K</span>
            </button>
          )}
          <ThemeToggle />
          {user && (
            <div className="flex items-center gap-2">
              <div className="flex items-center gap-1.5">
                {user.avatarUrl ? (
                  <img
                    src={user.avatarUrl}
                    alt={user.name ?? user.email}
                    className="w-6 h-6 rounded-full object-cover"
                  />
                ) : (
                  <div className="w-6 h-6 rounded-full bg-surface-2 text-slate-700 flex items-center justify-center text-2xs font-semibold uppercase">
                    {(user.name ?? user.email).charAt(0)}
                  </div>
                )}
                <span className="text-xs text-slate-600 hidden md:inline max-w-[120px] truncate">
                  {user.name ?? user.email}
                </span>
              </div>
              <button
                type="button"
                onClick={() => setShowPwChange(true)}
                className="px-2 py-1 rounded-md text-2xs text-slate-500 hover:text-slate-800 hover:bg-surface transition-colors"
              >
                {t('user.changePassword')}
              </button>
              <a
                href="/auth/logout"
                className="px-2 py-1 rounded-md text-2xs text-slate-500 hover:text-slate-800 hover:bg-surface transition-colors"
              >
                {t('user.logout')}
              </a>
            </div>
          )}
          {showPwChange && <ChangePasswordDialog onClose={() => setShowPwChange(false)} />}
        </div>
      </div>
    </div>
  );
}
