'use client';

import { captureCaught } from '@/lib/observability/capture';

type NavProgressPhase = 'idle' | 'loading' | 'completing';

type NavSpeedState = {
  progressPhase: NavProgressPhase;
  topBarVisible: boolean;
};

type NavSpeedProbe = {
  routeKey: string;
  requestedTop: number;
  restoredTop: number;
  restored: boolean;
};

type NavSpeedWindow = Window & {
  __NAV_SPEED_PROBE__?: NavSpeedProbe;
};

const PROGRESS_COMPLETE_DELAY_MS = 180;
const SCROLL_HIDE_THRESHOLD = 80;
const SCROLL_DELTA_THRESHOLD = 4;
const SCROLL_STORAGE_PREFIX = 'multideal:nav-scroll:';

let initialized = false;
let completionTimer = 0;
let pendingRestore = false;
let lastScrollY = 0;
let scrollRaf = 0;

const listeners = new Set<() => void>();

const SERVER_SNAPSHOT: NavSpeedState = {
  progressPhase: 'idle',
  topBarVisible: true,
};

let state: NavSpeedState = {
  progressPhase: 'idle',
  topBarVisible: true,
};

function routeKey(): string {
  return `${window.location.pathname}${window.location.search}`;
}

function storageKey(key: string): string {
  return `${SCROLL_STORAGE_PREFIX}${key}`;
}

function emit(): void {
  for (const listener of listeners) listener();
}

function setState(next: Partial<NavSpeedState>): void {
  state = { ...state, ...next };
  emit();
}

function clearCompletionTimer(): void {
  if (completionTimer) {
    window.clearTimeout(completionTimer);
    completionTimer = 0;
  }
}

function setProbe(probe: NavSpeedProbe): void {
  (window as NavSpeedWindow).__NAV_SPEED_PROBE__ = probe;
}

function writeScrollPosition(key: string, top: number): void {
  try {
    sessionStorage.setItem(storageKey(key), JSON.stringify({ top }));
  } catch (err) {
    captureCaught(err, { scope: 'lib.nav.navSpeed.writeScrollPosition', severity: 'info' });
    return;
  }
}

function readScrollPosition(key: string): number | null {
  try {
    const raw = sessionStorage.getItem(storageKey(key));
    if (!raw) return null;
    const parsed = JSON.parse(raw) as { top?: unknown };
    return typeof parsed.top === 'number' && Number.isFinite(parsed.top) ? parsed.top : null;
  } catch (err) {
    captureCaught(err, { scope: 'lib.nav.navSpeed.readScrollPosition', severity: 'info' });
    return null;
  }
}

function saveCurrentScroll(): void {
  writeScrollPosition(routeKey(), window.scrollY);
}

function handleTopBarVisibility(): void {
  const nextScrollY = window.scrollY;
  const shouldShow =
    nextScrollY <= SCROLL_DELTA_THRESHOLD ||
    nextScrollY < lastScrollY ||
    nextScrollY < SCROLL_HIDE_THRESHOLD;
  setState({ topBarVisible: shouldShow });
  lastScrollY = nextScrollY;
}

function restoreScrollIfNeeded(): void {
  const key = routeKey();
  if (!pendingRestore) {
    setProbe({ routeKey: key, requestedTop: 0, restoredTop: window.scrollY, restored: false });
    return;
  }

  pendingRestore = false;
  const savedTop = readScrollPosition(key);
  if (savedTop == null) {
    setProbe({ routeKey: key, requestedTop: 0, restoredTop: window.scrollY, restored: false });
    return;
  }

  requestAnimationFrame(() => {
    requestAnimationFrame(() => {
      window.scrollTo(0, savedTop);
      requestAnimationFrame(() => {
        setProbe({
          routeKey: key,
          requestedTop: savedTop,
          restoredTop: window.scrollY,
          restored: true,
        });
        handleTopBarVisibility();
      });
    });
  });
}

function beginProgress(): void {
  clearCompletionTimer();
  setState({ progressPhase: 'loading' });
}

function completeProgress(): void {
  clearCompletionTimer();
  setState({ progressPhase: 'completing' });
  completionTimer = window.setTimeout(() => {
    setState({ progressPhase: 'idle' });
  }, PROGRESS_COMPLETE_DELAY_MS);
}

function isSoftNavAnchor(target: EventTarget | null): target is HTMLAnchorElement {
  if (!(target instanceof Element)) return false;
  const anchor = target.closest('a[href]');
  if (!(anchor instanceof HTMLAnchorElement)) return false;
  if (anchor.target && anchor.target !== '_self') return false;
  if (anchor.hasAttribute('download')) return false;
  if (anchor.origin !== window.location.origin) return false;
  if (anchor.pathname === window.location.pathname && anchor.search === window.location.search) {
    return false;
  }
  return true;
}

function onDocumentClick(event: MouseEvent): void {
  if (event.defaultPrevented) return;
  if (event.button !== 0) return;
  if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
  if (!isSoftNavAnchor(event.target)) return;
  beginProgress();
  saveCurrentScroll();
}

function onScroll(): void {
  if (scrollRaf) return;
  scrollRaf = window.requestAnimationFrame(() => {
    scrollRaf = 0;
    saveCurrentScroll();
    handleTopBarVisibility();
  });
}

function initialize(): void {
  if (initialized || typeof window === 'undefined' || typeof document === 'undefined') return;
  initialized = true;
  lastScrollY = window.scrollY;
  setProbe({
    routeKey: routeKey(),
    requestedTop: 0,
    restoredTop: window.scrollY,
    restored: false,
  });
  document.addEventListener('click', onDocumentClick);
  document.addEventListener('astro:before-preparation', beginProgress as EventListener);
  document.addEventListener('astro:page-load', completeProgress as EventListener);
  document.addEventListener('astro:page-load', restoreScrollIfNeeded as EventListener);
  window.addEventListener('scroll', onScroll, { passive: true });
  window.addEventListener('pagehide', saveCurrentScroll);
  window.addEventListener('popstate', () => {
    pendingRestore = true;
    beginProgress();
  });
}

export function subscribeNavSpeed(listener: () => void): () => void {
  initialize();
  listeners.add(listener);
  return () => {
    listeners.delete(listener);
  };
}

export function getNavSpeedSnapshot(): NavSpeedState {
  initialize();
  return state;
}

export function getNavSpeedServerSnapshot(): NavSpeedState {
  return SERVER_SNAPSHOT;
}
