<script>
  import { onMount } from 'svelte'
  import { slides } from '@state/slides.svelte'

  let { data } = $props()

  // --- Constants ---
  const SCROLL_LOCK_MS    = 650   // ms before next scroll is accepted
  const WHEEL_DEBOUNCE_MS = 100   // ms window to accumulate wheel delta
  const WHEEL_THRESHOLD   = 25    // accumulated px to trigger navigation
  const TOUCH_THRESHOLD   = 50    // px swipe distance to trigger navigation
  const PLAY_DELAY_MS     = 300   // ms delay before starting playback on slide activation
  const REV_TARGET_MIN    = 0.1   // min revTarget to avoid pausing exactly at videoDuration

  // --- State ---
  let currentItem   = $state(0)
  let canScroll     = $state(true)
  let isReverse     = $state(false)
  let offsetY       = $state(0)
  let videoDuration = $state(0)

  // --- DOM refs ---
  let videoFwd      = $state(null)
  let videoRev      = $state(null)
  let textContainer = $state(null)
  let itemEls       = $state([])
  let sectionEl     = $state(null)

  // --- Plain variables (not reactive, used in event listeners) ---
  let fwdTarget      = null   // forward video pause target (seconds)
  let revTarget      = null   // reverse video pause target (seconds)
  // Position in the forward video timeline.
  // Updated from videoFwd.currentTime when going forward,
  // and mirrored from videoRev.currentTime when going in reverse.
  let currentFwdTime = 0

  // --- Derived ---
  const isActive  = $derived(slides.active?.id === 'expertise')
  const items     = $derived(data?.items ?? [])
  const itemCount = $derived(items.length)

  // segmentEnds[i] = timestamp where forward video pauses after reaching item i
  const segmentEnds = $derived(
    itemCount > 0 && videoDuration > 0
      ? Array.from({ length: itemCount }, (_, i) => videoDuration * (i + 1) / itemCount)
      : []
  )

  // --- Center active item vertically in viewport ---
  // Uses offsetTop which is NOT affected by CSS transforms
  // Requires position:relative on .expertise-text (see CSS below)
  function computeOffset() {
    if (!textContainer || !itemEls[currentItem]) return
    const wh          = window.innerHeight
    const wrapperRect = textContainer.parentElement.getBoundingClientRect()
    const el          = itemEls[currentItem]
    offsetY = wh / 2 - wrapperRect.top - el.offsetTop - el.offsetHeight / 2
  }

  // --- Video control helpers ---

  // Capture current position from whichever video is playing, then stop both.
  function stopActiveVideo() {
    if (videoFwd && !videoFwd.paused) {
      currentFwdTime = videoFwd.currentTime
      videoFwd.pause()
      fwdTarget = null
    }
    if (videoRev && !videoRev.paused) {
      currentFwdTime = videoDuration - videoRev.currentTime
      videoRev.pause()
      revTarget = null
    }
  }

  // Seek videoFwd to currentFwdTime and play until targetTime.
  // If currently showing the reverse video, wait for the seek before switching.
  function playForward(targetTime) {
    fwdTarget = targetTime
    if (videoFwd) videoFwd.currentTime = currentFwdTime
    if (isReverse) {
      videoFwd?.addEventListener('seeked', () => {
        isReverse = false
        videoFwd?.play().catch(() => {})
      }, { once: true })
    } else {
      videoFwd?.play().catch(() => {})
    }
  }

  // Seek videoRev to the mirror of currentFwdTime and play until targetTime.
  // If currently showing the forward video, wait for the seek before switching.
  function playReverse(targetTime) {
    const revStart = Math.max(0, videoDuration - currentFwdTime)
    revTarget = targetTime
    if (videoRev) videoRev.currentTime = revStart
    if (!isReverse) {
      videoRev?.addEventListener('seeked', () => {
        isReverse = true
        videoRev?.play().catch(() => {})
      }, { once: true })
    } else {
      videoRev?.play().catch(() => {})
    }
  }

  // --- Navigate: move one item up or down ---
  let scrollLockTimer = null   // internal state for navigate()
  function navigate(direction) {
    if (!canScroll || segmentEnds.length === 0) return

    const prevItem = currentItem
    const newItem  = direction === 'down'
      ? Math.min(prevItem + 1, itemCount - 1)
      : Math.max(prevItem - 1, 0)

    if (newItem === prevItem) return   // at boundary, ignore

    canScroll = false
    clearTimeout(scrollLockTimer)
    scrollLockTimer = setTimeout(() => { canScroll = true }, SCROLL_LOCK_MS)
    currentItem = newItem

    if (direction === 'down' && videoFwd && !videoFwd.paused) {
      // Fast path: forward video already playing — just move the stop point
      fwdTarget = segmentEnds[currentItem]

    } else if (direction === 'up' && videoRev && !videoRev.paused) {
      // Fast path: reverse video already playing — just move the stop point.
      // Read live currentTime because currentFwdTime is stale during play.
      const liveFwdPos  = videoDuration - videoRev.currentTime
      const segBoundary = segmentEnds[currentItem]
      const targetFwd   = liveFwdPos > segBoundary ? segBoundary : 0
      revTarget = videoDuration - Math.max(targetFwd, REV_TARGET_MIN)

    } else {
      // General case: stop whatever is playing, then start in the right direction
      stopActiveVideo()
      if (direction === 'down') {
        playForward(segmentEnds[currentItem])
      } else {
        const segBoundary = segmentEnds[currentItem]
        const targetFwd   = currentFwdTime > segBoundary ? segBoundary : 0
        playReverse(videoDuration - Math.max(targetFwd, REV_TARGET_MIN))
      }
    }

    requestAnimationFrame(() => { if (isActive) computeOffset() })
  }

  // --- Wheel capture (non-passive, attached in onMount) ---
  let scrollDelta  = 0   // internal state for onWheel()
  let lastScrollAt = 0
  function onWheel(e) {
    e.preventDefault()
    if (!isActive || !canScroll) return
    const now = Date.now()
    if (now - lastScrollAt > WHEEL_DEBOUNCE_MS) scrollDelta = 0
    lastScrollAt = now
    scrollDelta += e.deltaY
    if (Math.abs(scrollDelta) >= WHEEL_THRESHOLD) {
      navigate(scrollDelta > 0 ? 'down' : 'up')
      scrollDelta = 0
    }
  }

  // --- Touch ---
  let touchStartY = 0   // internal state for touch handlers
  function onTouchStart(e) { touchStartY = e.touches[0].clientY }
  function onTouchEnd(e) {
    if (!isActive || !canScroll) return
    const diff = touchStartY - e.changedTouches[0].clientY
    if (Math.abs(diff) >= TOUCH_THRESHOLD) navigate(diff > 0 ? 'down' : 'up')
  }

  // --- Keyboard ---
  function onKeyDown(e) {
    if (!isActive || !canScroll) return
    if (e.key === 'ArrowDown') { e.preventDefault(); navigate('down') }
    if (e.key === 'ArrowUp')   { e.preventDefault(); navigate('up') }
  }

  // --- Playback lifecycle ---
  function initPlayback() {
    setTimeout(() => {
      const tryPlay = () => {
        const dur = videoFwd?.duration
        if (!dur || itemCount === 0) return
        videoDuration        = dur
        videoFwd.currentTime = 0
        currentFwdTime       = 0
        isReverse            = false
        fwdTarget            = dur / itemCount   // = segmentEnds[0]
        videoFwd.play().catch(() => {})
        // Pre-seek reverse video to buffer the region needed for the first UP scroll
        if (videoRev) videoRev.currentTime = Math.max(0, dur - dur / itemCount)
        requestAnimationFrame(() => computeOffset())
      }
      if (videoFwd?.duration) {
        tryPlay()
      } else {
        videoFwd?.addEventListener('loadedmetadata', () => {
          videoDuration = videoFwd.duration
          tryPlay()
        }, { once: true })
      }
    }, PLAY_DELAY_MS)
  }

  function resetPlayback() {
    fwdTarget      = null
    revTarget      = null
    currentFwdTime = 0
    if (videoFwd) { videoFwd.pause(); videoFwd.currentTime = 0 }
    if (videoRev) { videoRev.pause(); videoRev.currentTime = 0 }
    currentItem = 0
    offsetY     = 0
    isReverse   = false
    canScroll   = true
    clearTimeout(scrollLockTimer)
  }

  // --- onMount: set up video listeners + wheel + resize ---
  onMount(() => {
    sectionEl?.addEventListener('wheel', onWheel, { passive: false })

    // Forward video: update currentFwdTime and pause when target is reached
    const onFwdUpdate = () => {
      if (!videoFwd || videoFwd.paused || fwdTarget === null) return
      if (videoFwd.currentTime >= fwdTarget) {
        currentFwdTime = videoFwd.currentTime
        videoFwd.pause()
        fwdTarget = null
      }
    }
    videoFwd?.addEventListener('timeupdate', onFwdUpdate)

    // Reverse video: update currentFwdTime (mirrored) and pause when target is reached
    const onRevUpdate = () => {
      if (!videoRev || videoRev.paused || revTarget === null) return
      if (videoRev.currentTime >= revTarget) {
        currentFwdTime = videoDuration - videoRev.currentTime
        videoRev.pause()
        revTarget = null
      }
    }
    videoRev?.addEventListener('timeupdate', onRevUpdate)

    const onResize = () => { if (isActive) computeOffset() }
    window.addEventListener('resize', onResize)
    window.addEventListener('orientationchange', onResize)
    window.addEventListener('keydown', onKeyDown)

    return () => {
      sectionEl?.removeEventListener('wheel', onWheel)
      videoFwd?.removeEventListener('timeupdate', onFwdUpdate)
      videoRev?.removeEventListener('timeupdate', onRevUpdate)
      window.removeEventListener('resize', onResize)
      window.removeEventListener('orientationchange', onResize)
      window.removeEventListener('keydown', onKeyDown)
      clearTimeout(scrollLockTimer)
    }
  })

  // --- Effect: react to slide activation / deactivation ---
  $effect(() => {
    if (isActive) {
      initPlayback()
    } else {
      resetPlayback()
    }
  })
</script>

<section
  class="expertise golden-grid slide"
  aria-label="Expertise"
  bind:this={sectionEl}
  ontouchstart={onTouchStart}
  ontouchend={onTouchEnd}
>
  <!-- Video background (decorative) -->
  <div class="expertise-bg" aria-hidden="true">
    <video
      bind:this={videoFwd}
      class:active={!isReverse}
      muted
      playsinline
      preload="auto"
    >
      <source src="/assets/video/BACKGROUND_VIDEO_MISSION.mp4" type="video/mp4" />
    </video>
    <video
      bind:this={videoRev}
      class:active={isReverse}
      muted
      playsinline
      preload="auto"
    >
      <source src="/assets/video/BACKGROUND_VIDEO_MISSION_REVERSE.mp4" type="video/mp4" />
    </video>
  </div>

  <!-- Decorative vertical lines -->
  <div class="vertical-line vertical-line-col8"  aria-hidden="true"></div>
  <div class="vertical-line vertical-line-col14" aria-hidden="true"></div>

  <!-- Title -->
  <h2 class="expertise-title font-face-terminal">
    {@html data?.pageTitle ?? ''}
  </h2>

  <!-- Sliding text container -->
  <div class="expertise-text-wrapper" aria-live="polite" aria-atomic="true">
    <div
      class="expertise-text"
      bind:this={textContainer}
      style="transform: translateY({offsetY}px)"
    >
      {#each items as item, i}
        <div
          class="expertise-item"
          class:active={i === currentItem}
          bind:this={itemEls[i]}
        >
          {@html item.text}
        </div>
      {/each}
    </div>
  </div>
</section>

<style>
  .expertise {
    background-color: #000;
  }

  :global(.expertise-item p) {
    margin-bottom: 1rem;
  }

  /* Full-grid video background */
  .expertise-bg {
    grid-area: 1/1 / span 20 / span 20;
    position: relative;
    overflow: hidden;
  }

  .expertise-bg video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: none;
  }

  .expertise-bg video.active {
    display: block;
  }

  /* Custom vertical lines */
  .vertical-line-col8 {
    grid-area: 1/8 / span 20 / span 1;
  }

  .vertical-line-col14 {
    grid-area: 1/14 / span 20 / span 1;
  }

  /* Title */
  .expertise-title {
    grid-area: 8/6 / span 5 / span 5;
    z-index: var(--z-content);
    text-align: left;
    font-size: var(--font-size-title-hero);
    color: var(--color-text);
    align-self: center;
    line-height: 1;
  }

  /* Wrapper clips the sliding container */
  .expertise-text-wrapper {
    grid-area: 8/11 / span 7 / span 6;
    overflow: hidden;
    z-index: var(--z-content);
    display: flex;
    align-items: flex-start;
  }

  /* Sliding container — position:relative so el.offsetTop is relative to this element
     (CSS transforms do NOT affect offsetTop, so computeOffset() is always accurate) */
  .expertise-text {
    position: relative;
    width: 100%;
    transition: transform 0.6s cubic-bezier(0.77, 0, 0.175, 1);
  }

  /* Individual text items */
  .expertise-item {
    font-size: var(--font-size-expertise);
    color: var(--color-text);
    text-align: left;
    line-height: 1.4;
    margin-bottom: 50px;
    opacity: 0.3;
    transform: scale(0.9);
    transform-origin: left center;
    transition: opacity 0.5s ease, transform 0.5s ease;
  }

  .expertise-item.active {
    opacity: 1;
    transform: scale(1);
  }

  /* Mobile (≤ 700px) */
  @media screen and (max-width: 700px) {
    .expertise-title {
      grid-area: 5/4 / span 1 / span 7;
      font-size: var(--font-size-title-main-mobile);
    }

    .expertise-text-wrapper {
      grid-area: 6/4 / span 8 / span 14;
    }

    .expertise-item {
      font-size: var(--font-size-expertise-mobile);
    }
  }

  /* Tablet (701–912px) */
  @media screen and (min-width: 701px) and (max-width: 912px) {
    .expertise-title {
      grid-area: 5/6 / span 4 / span 12;
      font-size: var(--font-size-title-main-tablet);
    }

    .expertise-text-wrapper {
      grid-area: 8/6 / span 8 / span 10;
    }

    .expertise-item {
      font-size: var(--font-size-expertise-tablet);
    }
  }

  /* Reduced motion */
  @media (prefers-reduced-motion: reduce) {
    .expertise-text,
    .expertise-item {
      transition: none;
    }
  }
</style>
