<template>
  <div ref="layoutRef" class="lifewave-layout" :class="{ 'lifewave-layout--dark': isDark }">
    <!-- FloatingLines Fullscreen Background (always visible) -->
    <FloatingLines
      ref="floatingLinesRef"
      class="lifewave-layout__background"
      :line-count="[fl.lineCount]"
      :animation-speed="fl.speed"
      :num-points="shaderNumPoints"
      :point-x-values="shaderPointXBase"
      :scroll-container="scrollContainerEl"
      :scroll-uv-scale="scrollUvScale"
      :point-y-values="shaderPointY"
      :point-colors="shaderPointColors"
      :line-spread="fl.spread"
      :fan-spread="fl.fanSpread"
      :line-sharpness="fl.lineSharpness"
      :wave-frequency="fl.waveFrequency"
      :bezier-curvature="fl.bezierCurvature"
      :circle-radius-px="fl.circleRadius"
      :circle-glow-size="fl.glowSize"
      :circle-glow-strength="fl.glowStrength"
      :line-brightness="fl.lineBrightness ?? 1"
      :lines-gradient="parsedGradient"
      :bg-color-center="fl.bgCenter"
      :bg-color-edge="fl.bgEdge"
      :background-image="fl.backgroundImage"
      :mix-blend-mode="'screen'"
    />

    <!-- Scrollable Timeline -->
    <TimelineView
      ref="timelineViewRef"
      class="lifewave-layout__timeline"
      @dot-select="onDotSelect"
      @view-update="onViewUpdate"
    />

    <!-- Header -->
    <header class="lifewave-header">
      <span class="lifewave-header__logo" @click="toggleDarkMode">ThatsMe</span>
      <button class="lifewave-header__user glass--button" @click="userMenuOpen = !userMenuOpen">
        <q-icon name="person" size="22px" :color="isDark ? 'white' : 'grey-8'" />
      </button>
    </header>

    <!-- FPS Overlay -->
    <div v-if="settingsStore.showFps" class="lifewave-fps">
      {{ floatingLinesRef?.fpsDisplay ?? 0 }} FPS
      <span class="lifewave-fps__dpr">{{ floatingLinesRef?.dprDisplay ?? '0' }}x</span>
    </div>

    <!-- Content -->
    <main class="lifewave-content">
      <router-view />
    </main>

    <!-- Zoom Control (Left Side) — hidden when panel is open -->
    <ZoomControl
      v-if="!eventsStore.panelOpen"
      class="lifewave-layout__zoom"
      :zoom="currentZoom"
      :min="zoomMin"
      :max="zoomMax"
      @zoom-in="timelineViewRef?.zoomIn()"
      @zoom-out="timelineViewRef?.zoomOut()"
      @zoom-to="onZoomTo"
    />

    <!-- Settings Button (Bottom-Left, below zoom) — hidden when panel is open -->
    <button
      v-if="!eventsStore.panelOpen"
      class="lifewave-settings-btn glass--button"
      @click="settingsOpen = !settingsOpen"
    >
      <q-icon name="tune" size="22px" :color="isDark ? 'white' : 'grey-8'" />
    </button>

    <!-- Add Event Button (Bottom-Center) — hidden when panel is open -->
    <AddEventButton v-if="!eventsStore.panelOpen" @click="onAddEvent" />

    <!-- Backdrop blur when panel is open -->
    <Transition name="fade">
      <div
        v-if="eventsStore.panelOpen"
        class="lifewave-backdrop"
        @click="eventsStore.closePanel()"
      />
    </Transition>

    <!-- Event Panel (Slide-Up) -->
    <EventPanel />

    <!-- Wave Settings Backdrop -->
    <Transition name="fade">
      <div
        v-if="settingsOpen && !eventsStore.panelOpen"
        class="lifewave-backdrop lifewave-backdrop--no-blur"
        @click="settingsOpen = false"
      />
    </Transition>

    <!-- Wave Settings Panel (Slide-Up) -->
    <LifeWaveSettings
      :open="settingsOpen && !eventsStore.panelOpen"
      @close="settingsOpen = false"
    />

    <!-- User Menu Backdrop -->
    <Transition name="fade">
      <div
        v-if="userMenuOpen"
        class="lifewave-backdrop"
        @click="userMenuOpen = false"
      />
    </Transition>

    <!-- User Menu (Slide from right) -->
    <UserMenu
      :open="userMenuOpen"
      @close="userMenuOpen = false"
      @navigate="onUserMenuNavigate"
    />

    <!-- App Settings Modal Backdrop -->
    <Transition name="fade">
      <div
        v-if="appSettingsOpen"
        class="lifewave-backdrop"
        @click="appSettingsOpen = false"
      />
    </Transition>

    <!-- App Settings Modal -->
    <AppSettingsModal
      :open="appSettingsOpen"
      @close="appSettingsOpen = false"
    />
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import { useQuasar } from 'quasar'
import AddEventButton from 'components/AddEventButton.vue'
import EventPanel from 'components/EventPanel.vue'
import FloatingLines from 'components/FloatingLines.vue'
import LifeWaveSettings from 'components/LifeWaveSettings.vue'
import TimelineView from 'components/TimelineView.vue'
import AppSettingsModal from 'components/AppSettingsModal.vue'
import UserMenu from 'components/UserMenu.vue'
import ZoomControl from 'components/ZoomControl.vue'
import { useEventsStore } from 'stores/events'
import { useSettingsStore } from 'stores/settings'

const $q = useQuasar()
const eventsStore = useEventsStore()
const settingsStore = useSettingsStore()
const isDark = computed(() => $q.dark.isActive)
const settingsOpen = ref(false)
const userMenuOpen = ref(false)
const appSettingsOpen = ref(false)
const floatingLinesRef = ref(null)
const fl = computed(() => settingsStore.floatingLines)

// Timeline view ref (for direct scroll access in render loop)
const timelineViewRef = ref(null)
const scrollContainerEl = computed(() => timelineViewRef.value?.timelineRef ?? null)

// Layout dimensions (for screen→UV conversion)
const layoutRef = ref(null)
const layoutWidth = ref(window.innerWidth)
const layoutHeight = ref(window.innerHeight)
let layoutResizeObserver = null

onMounted(() => {
  if (layoutRef.value) {
    layoutWidth.value = layoutRef.value.clientWidth
    layoutHeight.value = layoutRef.value.clientHeight
    layoutResizeObserver = new ResizeObserver(() => {
      layoutWidth.value = layoutRef.value.clientWidth
      layoutHeight.value = layoutRef.value.clientHeight
    })
    layoutResizeObserver.observe(layoutRef.value)
  }
})

onBeforeUnmount(() => {
  layoutResizeObserver?.disconnect()
})

// Timeline state (received from TimelineView via emit)
const timelineState = ref(null)

function onViewUpdate(state) {
  timelineState.value = state
}

// Convert screen pixel coordinates → shader UV space
// Shader: baseUv = (2*fragCoord - iResolution) / iResolution.y; baseUv.y *= -1;
// For CSS pixel (sx, sy) from top-left:
//   uvX = (2*sx - cssWidth) / cssHeight
//   uvY = (2*sy - cssHeight) / cssHeight
function screenToUV(sx, sy) {
  const w = layoutWidth.value
  const h = layoutHeight.value
  return {
    x: (2 * sx - w) / h,
    y: (2 * sy - h) / h
  }
}

// Compute shader point positions from event positions
const TIMELINE_TOP = 40 // CSS: .timeline-container { top: 40px }

// Select up to 8 points from visible window + boundary events for shader lines
const shaderSelection = computed(() => {
  if (!timelineState.value) return []
  const { events, visibleStart, visibleEnd } = timelineState.value
  if (events.length === 0) return []

  // Include 3 events before and after visible range for smooth line continuity
  const rangeStart = Math.max(0, (visibleStart ?? 0) - 3)
  const rangeEnd = Math.min(events.length - 1, (visibleEnd ?? events.length - 1) + 3)

  let candidates = events.slice(rangeStart, rangeEnd + 1)

  // If more than 16, subsample evenly (keep first + last)
  if (candidates.length > 16) {
    const sampled = [candidates[0]]
    const step = (candidates.length - 1) / 15
    for (let i = 1; i < 15; i++) {
      sampled.push(candidates[Math.round(i * step)])
    }
    sampled.push(candidates[candidates.length - 1])
    candidates = sampled
  }

  return candidates
})

const shaderNumPoints = computed(() => shaderSelection.value.length)

// Base X positions in UV space WITHOUT scroll offset.
// FloatingLines applies the live scrollLeft in its render loop for perfect sync.
const shaderPointXBase = computed(() => {
  const xs = Array(16).fill(0)
  const sel = shaderSelection.value
  const w = layoutWidth.value
  const h = layoutHeight.value
  for (let i = 0; i < sel.length; i++) {
    xs[i] = (2 * sel[i].x - w) / h
  }
  return xs
})

// Scale factor to convert scrollLeft pixels → UV offset
const scrollUvScale = computed(() => 2.0 / layoutHeight.value)

const shaderPointY = computed(() => {
  const ys = Array(16).fill(0)
  if (!timelineState.value) return ys
  const sel = shaderSelection.value
  const tlHeight = timelineState.value.containerHeight
  for (let i = 0; i < sel.length; i++) {
    const yPercent = 48 - sel[i].emotion * 30
    const screenY = TIMELINE_TOP + (yPercent / 100) * tlHeight
    ys[i] = screenToUV(0, screenY).y
  }
  return ys
})

const shaderPointColors = computed(() => {
  return shaderSelection.value.map(e => e.color || '#ffffff')
})

// Parse gradient stops from textarea string
const parsedGradient = computed(() => {
  return fl.value.gradientStops
    .split('\n')
    .map(s => s.trim())
    .filter(s => s.length > 0 && s.startsWith('#'))
})

// Zoom state from TimelineView
const currentZoom = computed(() => timelineViewRef.value?.zoomLevel ?? 1)
const zoomMin = computed(() => timelineViewRef.value?.MIN_ZOOM ?? 0.4)
const zoomMax = computed(() => timelineViewRef.value?.MAX_ZOOM ?? 3.0)

function onZoomTo(value) {
  if (!timelineViewRef.value) return
  const clamped = Math.min(zoomMax.value, Math.max(zoomMin.value, value))
  // Use applyZoom exposed or set directly — we use the internal method indirectly
  // by computing step from current to target
  const tv = timelineViewRef.value
  const el = tv.timelineRef
  if (!el) return
  const cx = el.clientWidth / 2
  const worldX = el.scrollLeft + cx
  const ratio = clamped / tv.zoomLevel
  tv.zoomLevel = clamped
  // Restore scroll position to keep center stable
  requestAnimationFrame(() => {
    el.scrollLeft = worldX * ratio - cx
  })
}

const toggleDarkMode = () => {
  $q.dark.toggle()
}

const onAddEvent = () => {
  eventsStore.openPanel()
}

const onDotSelect = (id) => {
  eventsStore.selectEvent(id)
  eventsStore.openPanel(id)
}

const onUserMenuNavigate = (target) => {
  userMenuOpen.value = false
  if (target === 'settings') {
    appSettingsOpen.value = true
  }
}
</script>

<style scoped>
.lifewave-layout {
  position: relative;
  width: 100%;
  height: 100dvh;
  overflow: hidden;
  background: #000;
  color: #F5F5F5;
  transition: background 0.3s ease, color 0.3s ease;
  touch-action: pan-x pan-y;
}

.lifewave-layout--dark {
  background: #000;
  color: #F5F5F5;
}

/* FloatingLines Background */
.lifewave-layout__background {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* Timeline — positioning comes from TimelineView's own .timeline class */
.lifewave-layout__timeline {
  z-index: 5;
}

/* Header */
.lifewave-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
}

.lifewave-header__logo {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.3px;
  cursor: pointer;
  user-select: none;
}

.lifewave-header__user {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
}

/* Zoom Control */
.lifewave-layout__zoom {
  position: fixed;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 10;
}

/* Settings Button — bottom-left, below zoom */
.lifewave-settings-btn {
  position: fixed;
  bottom: 16px;
  left: 12px;
  z-index: 10;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  color: #F5F5F5;
}
.lifewave-settings-btn--dark {
  color: #000;
}
/* Content */
.lifewave-content {
  padding-top: 72px;
  height: 100%;
}

/* Backdrop blur overlay */
.lifewave-backdrop {
  position: fixed;
  inset: 0;
  z-index: 15;
  background: rgba(0, 0, 0, 0.15);
  backdrop-filter: blur(1px);
  -webkit-backdrop-filter: blur(1px);
}

.lifewave-backdrop--no-blur {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

/* FPS Overlay */
.lifewave-fps {
  position: fixed;
  top: 52px;
  right: 16px;
  z-index: 30;
  padding: 4px 10px;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.6);
  color: #0f0;
  font-family: 'SF Mono', 'Menlo', monospace;
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  pointer-events: none;
  user-select: none;
}

.lifewave-fps__dpr {
  color: #999;
  margin-left: 6px;
}
</style>
