<script lang="ts">
  import type { Snippet } from 'svelte';
  import Header from './Header.svelte';
  import AdBanner from './AdBanner.svelte';
  import { navigate } from '../lib/router.svelte';

  // The app-shell layout (all screens): the nav bar grows; the ad strip, content and
  // optional tab bar pin to the bottom (ad directly above the content). Pass `scroll`
  // false for screens that own their vertical fit (the game board).
  let {
    title,
    back,
    tabbar,
    children,
    scroll = true,
    growNav = false,
    column = false,
  }: {
    title: string;
    back?: string;
    tabbar?: Snippet;
    children?: Snippet;
    scroll?: boolean;
    growNav?: boolean;
    // column lays the content out as a flex column so a child can own the vertical fit
    // (the game makes only its board scroll while the score/rack/tab bar stay put).
    column?: boolean;
  } = $props();

  // The promotional banner is feature-gated OFF until it is polished after release. The flag is
  // a compile-time `false`, so the {#if} branch — and with it the AdBanner import and its
  // banner.ts logic — is dead-code-eliminated from the production bundle. Flip to
  // true to bring it back.
  const SHOW_AD_BANNER = false;

  // Edge-swipe back: a rightward drag begun in the left band returns to `back`, the standard
  // mobile gesture (instant on release — the route slide plays the animation). Listened at the
  // window in the CAPTURE phase so the board's own pointer handlers (which capture/stop the
  // event) can never swallow it; touch/pen only. The band is a fraction of the viewport width
  // (EDGE_FRACTION — widen/narrow there). A hit-test keeps the wider band clear of the gestures
  // it would otherwise hijack: the rack (tile lift/reorder), a draggable pending tile, a
  // zoomed-in board (it pans), and text inputs.
  const EDGE_FRACTION = 0.2;
  const SWIPE_SKIP = '[data-rack], .cell.pending, .viewport.zoomed, input, textarea, select';
  $effect(() => {
    function onDown(e: PointerEvent) {
      if (!back || e.pointerType === 'mouse' || e.clientX > window.innerWidth * EDGE_FRACTION) return;
      if (document.elementFromPoint(e.clientX, e.clientY)?.closest(SWIPE_SKIP)) return;
      const x0 = e.clientX;
      const y0 = e.clientY;
      const onUp = (ev: PointerEvent) => {
        window.removeEventListener('pointerup', onUp, true);
        const dx = ev.clientX - x0;
        const dy = ev.clientY - y0;
        if (back && dx > 64 && Math.abs(dx) > Math.abs(dy) * 1.4) navigate(back);
      };
      window.addEventListener('pointerup', onUp, true);
    }
    window.addEventListener('pointerdown', onDown, true);
    return () => window.removeEventListener('pointerdown', onDown, true);
  });
</script>

<div class="screen">
  <Header {title} {back} grow={growNav} />
  {#if SHOW_AD_BANNER}<AdBanner />{/if}
  <main class="content" class:scroll class:fill={!growNav} class:column>{@render children?.()}</main>
  {#if tabbar}
    <nav class="tabbar">{@render tabbar()}</nav>
  {/if}
</div>

<style>
  .screen {
    display: flex;
    flex-direction: column;
    /* Fit the visible viewport (set from visualViewport, app.svelte.ts) so a screen with a
       bottom input — chat, word-check — stays above an open soft keyboard without the page
       scrolling; falls back to the full height where the var is unset. */
    height: var(--vvh, 100%);
  }
  .content {
    flex: 0 1 auto;
    min-height: 0;
  }
  .content.fill {
    flex: 1 1 auto;
  }
  .content.scroll {
    overflow-y: auto;
  }
  .content.column {
    display: flex;
    flex-direction: column;
  }
  .tabbar {
    flex: 0 0 auto;
  }
</style>
