<script lang="ts">
  import { onMount } from 'svelte';
  import { navigating, page } from '$app/stores';
  import { afterNavigate, disableScrollHandling } from '$app/navigation';
  import { initClickTracking, trackPageView } from '$lib/analytics';
  import MobileBookBar from '$lib/components/ui/MobileBookBar.svelte';
  import RouteSkeleton from '$lib/components/ui/RouteSkeleton.svelte';
  import { isMobileCtaButtonEnabled } from '$lib/feature-flags';
  import readex400Woff2 from '@fontsource/readex-pro/files/readex-pro-latin-400-normal.woff2?url';
  import readex700Woff2 from '@fontsource/readex-pro/files/readex-pro-latin-700-normal.woff2?url';
  import '@fontsource/readex-pro/latin-400.css';
  import '@fontsource/readex-pro/latin-500.css';
  import '@fontsource/readex-pro/latin-600.css';
  import '@fontsource/readex-pro/latin-700.css';
  import unbounded700Woff2 from '@fontsource/unbounded/files/unbounded-latin-700-normal.woff2?url';
  import unbounded800Woff2 from '@fontsource/unbounded/files/unbounded-latin-800-normal.woff2?url';
  import '@fontsource/unbounded/latin-400.css';
  import '@fontsource/unbounded/latin-600.css';
  import '@fontsource/unbounded/latin-700.css';
  import '@fontsource/unbounded/latin-800.css';
  import '@fortawesome/fontawesome-free/css/fontawesome.min.css';
  import '@fortawesome/fontawesome-free/css/solid.min.css';
  import '@fortawesome/fontawesome-free/css/brands.min.css';
  import '$lib/styles/variables.css';
  import '$lib/styles/base.css';
  import '$lib/styles/layout.css';
  import '$lib/styles/typography.css';
  import '$lib/styles/buttons.css';
  import '$lib/styles/forms.css';
  import '$lib/styles/sections.css';
  import '$lib/styles/motion.css';
  import '$lib/styles/responsive.css';

  const mobileCtaButtonEnabled = isMobileCtaButtonEnabled();

  let revealObserver: IntersectionObserver | null = null;
  const scrollStoragePrefix = 'goodwalk:scroll:';

  function getScrollStorageKey(urlLike: string) {
    const url = new URL(urlLike, 'http://goodwalk.local');
    return `${scrollStoragePrefix}${url.pathname}${url.search}`;
  }

  function saveScrollPosition(urlLike = window.location.href) {
    if (typeof window === 'undefined') return;

    sessionStorage.setItem(getScrollStorageKey(urlLike), String(window.scrollY));
  }

  function restoreScrollPosition(urlLike = window.location.href) {
    if (typeof window === 'undefined' || window.location.hash) return;

    const saved = sessionStorage.getItem(getScrollStorageKey(urlLike));
    if (!saved) return;

    const top = Number(saved);
    if (!Number.isFinite(top)) return;

    requestAnimationFrame(() => {
      requestAnimationFrame(() => {
        window.scrollTo({ top, left: 0, behavior: 'auto' });
      });
    });
  }

  function shouldAnimateAnchorBounce() {
    return typeof window !== 'undefined' && window.innerWidth > 768;
  }

  function initReveal() {
    revealObserver?.disconnect();

    const targets = document.querySelectorAll<HTMLElement>(
      '.section-heading, .service-card, .testimonial-card, .value-card'
    );

    targets.forEach(el => {
      el.setAttribute('data-reveal', '');
    });

    revealObserver = new IntersectionObserver(
      (entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            entry.target.classList.add('is-visible');
            revealObserver?.unobserve(entry.target);
          }
        });
      },
      { rootMargin: '0px 0px -40px 0px', threshold: 0.08 }
    );

    targets.forEach(el => revealObserver!.observe(el));
  }

  function bounceSection(hash: string) {
    if (!shouldAnimateAnchorBounce()) return;

    const id = hash.startsWith('#') ? hash.slice(1) : hash;
    if (!id) return;
    // Wait for smooth scroll to finish before playing the bounce
    setTimeout(() => {
      const el = document.getElementById(id);
      if (!el) return;
      el.classList.remove('anchor-bounce');
      void el.offsetWidth; // force reflow so re-adding the class re-triggers
      el.classList.add('anchor-bounce');
      el.addEventListener('animationend', () => el.classList.remove('anchor-bounce'), { once: true });
    }, 520);
  }

  onMount(() => {
    const cleanupClickTracking = initClickTracking();
    requestAnimationFrame(initReveal);

    restoreScrollPosition();

    // Same-page hash clicks aren't caught by afterNavigate
    function onHashChange() {
      bounceSection(window.location.hash);
    }

    function onPageHide() {
      saveScrollPosition();
    }

    function onVisibilityChange() {
      if (document.visibilityState === 'hidden') {
        saveScrollPosition();
      }
    }

    function onPageShow(event: PageTransitionEvent) {
      if (event.persisted) {
        restoreScrollPosition();
      }
    }

    window.addEventListener('hashchange', onHashChange);
    window.addEventListener('pagehide', onPageHide);
    window.addEventListener('pageshow', onPageShow);
    document.addEventListener('visibilitychange', onVisibilityChange);

    return () => {
      cleanupClickTracking();
      window.removeEventListener('hashchange', onHashChange);
      window.removeEventListener('pagehide', onPageHide);
      window.removeEventListener('pageshow', onPageShow);
      document.removeEventListener('visibilitychange', onVisibilityChange);
    };
  });

  function shouldShowSkeleton() {
    const navigation = $navigating;

    if (!navigation?.to?.url) {
      return false;
    }

    const fromPath = navigation.from?.url.pathname ?? $page.url.pathname;
    const toPath = navigation.to.url.pathname;

    if (navigation.to.url.hash && toPath === fromPath) {
      return false;
    }

    return toPath !== fromPath;
  }

  $: loadingPath = $navigating?.to?.url.pathname ?? $page.url.pathname;
  $: showRouteSkeleton = shouldShowSkeleton();

  afterNavigate(({ from, to }) => {
    if (!from || !to) return;

    if (to.url.hash && from.url.pathname !== to.url.pathname) {
      bounceSection(to.url.hash);
      return;
    }

    if (to.url.hash) {
      return;
    }

    if (from.url.pathname !== to.url.pathname) {
      disableScrollHandling();

      if (document.activeElement instanceof HTMLElement) {
        document.activeElement.blur();
      }

      requestAnimationFrame(() => {
        requestAnimationFrame(() => {
          window.scrollTo({ top: 0, left: 0, behavior: 'auto' });
          document.documentElement.scrollTop = 0;
          document.body.scrollTop = 0;
          initReveal();
        });
      });

      trackPageView(to.url.pathname + to.url.search, document.title);
    }
  });
</script>

<svelte:head>
  <link rel="preload" href={readex400Woff2} as="font" type="font/woff2" crossorigin="anonymous" />
  <link rel="preload" href={readex700Woff2} as="font" type="font/woff2" crossorigin="anonymous" />
  <link rel="preload" href={unbounded700Woff2} as="font" type="font/woff2" crossorigin="anonymous" />
  <link rel="preload" href={unbounded800Woff2} as="font" type="font/woff2" crossorigin="anonymous" />
</svelte:head>

<svelte:body class:mobile-cta-enabled={mobileCtaButtonEnabled} />

<div class="layout-shell">
  <div class:layout-content-loading={showRouteSkeleton} class="layout-content" aria-hidden={showRouteSkeleton}>
    <slot />
  </div>

  {#if showRouteSkeleton}
    <div class="layout-skeleton-layer" role="status" aria-label="Loading page" aria-live="polite">
      <RouteSkeleton pathname={loadingPath} />
    </div>
  {/if}
</div>

<MobileBookBar />

<style>
  .layout-shell {
    position: relative;
  }

  .layout-content-loading {
    visibility: hidden;
  }

  .layout-skeleton-layer {
    position: fixed;
    inset: 0;
    z-index: 30;
    overflow-y: auto;
    background: rgba(251, 251, 251, 0.98);
  }
</style>
