<template>
  <v-container class="pt-2 pb-6" max-width="900">
    <!-- In-context view: deep-linked to one post, with bidirectional infinite
         scroll — newer posts load above, older posts below. -->
    <template v-if="postIdFilter != null">
      <v-btn
        variant="text" size="small" prepend-icon="mdi-arrow-left"
        :to="{ name: 'posts' }" class="mb-2"
      >All posts</v-btn>

      <v-alert v-if="store.error" type="error" variant="tonal" closable class="mb-3">
        {{ String(store.error) }}
      </v-alert>

      <div v-if="store.loading && store.items.length === 0" class="fc-posts__loading">
        <v-progress-circular indeterminate color="accent" size="36" />
      </div>

      <div v-else>
        <div ref="topSentinel" class="fc-posts__sentinel">
          <v-progress-circular
            v-if="store.loading && !store.doneNewer"
            indeterminate color="accent" size="20"
          />
          <span v-else-if="store.doneNewer" class="fc-posts__end">Top of feed</span>
        </div>

        <div
          v-for="p in store.items" :key="p.id" :id="`fc-post-${p.id}`"
          :class="['fc-posts__entry', { 'fc-posts__entry--anchor': p.id === store.anchorId }]"
        >
          <PostCard :post="p" />
        </div>

        <div ref="bottomSentinel" class="fc-posts__sentinel">
          <v-progress-circular
            v-if="store.loading && !store.doneOlder"
            indeterminate color="accent" size="24"
          />
          <span v-else-if="store.doneOlder" class="fc-posts__end">End of stream</span>
        </div>
      </div>
    </template>

    <!-- Normal feed -->
    <template v-else>
      <PostsFilterBar
        :artist-id="artistFilter"
        :platform="platformFilter"
        @update:filters="onFilters"
      />

      <v-alert v-if="store.error" type="error" variant="tonal" closable class="mb-3">
        {{ String(store.error) }}
      </v-alert>

      <div v-if="store.loading && store.items.length === 0" class="fc-posts__loading">
        <v-progress-circular indeterminate color="accent" size="36" />
      </div>

      <div v-else-if="store.items.length === 0 && store.done" class="fc-posts__empty">
        <p v-if="hasActiveFilter">No posts match your search or filters.</p>
        <p v-else>No posts yet. Subscribe to a source on the
          <RouterLink to="/subscriptions">Subscriptions</RouterLink>
          tab to start capturing posts.
        </p>
      </div>

      <div v-else>
        <PostCard v-for="p in store.items" :key="p.id" :post="p" />

        <div ref="sentinel" class="fc-posts__sentinel">
          <v-progress-circular v-if="store.loading" indeterminate color="accent" size="24" />
          <span v-else-if="store.done" class="fc-posts__end">End of stream</span>
        </div>
      </div>
    </template>
  </v-container>
</template>

<script setup>
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { usePostsStore } from '../stores/posts.js'
import PostsFilterBar from '../components/posts/PostsFilterBar.vue'
import PostCard from '../components/posts/PostCard.vue'

const route = useRoute()
const router = useRouter()
const store = usePostsStore()

const artistFilter = computed(() => {
  const raw = route.query.artist_id
  return raw == null ? null : Number(raw)
})
const platformFilter = computed(() => route.query.platform || null)
const searchFilter = computed(() => route.query.q || null)
const postIdFilter = computed(() => {
  const raw = route.query.post_id
  return raw == null ? null : Number(raw)
})
const hasActiveFilter = computed(() =>
  artistFilter.value != null || platformFilter.value != null || searchFilter.value != null
)

// --- normal feed (downward infinite scroll) ---
const sentinel = ref(null)
let observer = null

async function reload() {
  await store.loadInitial({
    artist_id: artistFilter.value,
    platform: platformFilter.value,
    q: searchFilter.value,
  })
}
function onFilters({ artist_id, platform }) {
  const q = { ...route.query }
  if (artist_id == null) delete q.artist_id
  else q.artist_id = String(artist_id)
  if (!platform) delete q.platform
  else q.platform = platform
  router.replace({ query: q })
}
function teardownFeed() {
  if (observer) { observer.disconnect(); observer = null }
}
function setupFeedObserver() {
  teardownFeed()
  if (!sentinel.value) return
  observer = new IntersectionObserver((entries) => {
    if (entries.some((e) => e.isIntersecting)) store.loadMore()
  }, { rootMargin: '400px 0px' })
  observer.observe(sentinel.value)
}

// --- in-context view (bidirectional, anchored on a post) ---
const topSentinel = ref(null)
const bottomSentinel = ref(null)
let topObs = null
let bottomObs = null

function teardownAround() {
  if (topObs) { topObs.disconnect(); topObs = null }
  if (bottomObs) { bottomObs.disconnect(); bottomObs = null }
}
function setupAroundObservers() {
  teardownAround()
  bottomObs = new IntersectionObserver((entries) => {
    if (entries.some((e) => e.isIntersecting)) store.loadOlder()
  }, { rootMargin: '500px 0px' })
  if (bottomSentinel.value) bottomObs.observe(bottomSentinel.value)

  topObs = new IntersectionObserver(async (entries) => {
    if (!entries.some((e) => e.isIntersecting)) return
    if (store.loading || store.doneNewer) return
    // Preserve the viewport position across an upward prepend so the page
    // doesn't jump when newer posts insert above the current view.
    const beforeH = document.documentElement.scrollHeight
    const beforeY = window.scrollY
    await store.loadNewer()
    await nextTick()
    const afterH = document.documentElement.scrollHeight
    window.scrollTo(0, beforeY + (afterH - beforeH))
  }, { rootMargin: '200px 0px' })
  if (topSentinel.value) topObs.observe(topSentinel.value)
}
async function loadAroundAndAnchor() {
  teardownFeed()
  // Pass artist_id + platform through so the anchored view stays
  // scoped — the older/newer infinite scrolls then read these filters
  // back via the store's _aroundParams (operator-flagged 2026-06-01:
  // post-title click from the modal landed scoped but the scroll then
  // pulled unfiltered global posts).
  await store.loadAround(postIdFilter.value, {
    artist_id: artistFilter.value,
    platform: platformFilter.value,
    q: searchFilter.value,
  })
  await nextTick()
  const el = document.getElementById(`fc-post-${store.anchorId}`)
  if (el) el.scrollIntoView({ block: 'center' })
  setupAroundObservers()
}

async function activate() {
  if (postIdFilter.value != null) {
    await loadAroundAndAnchor()
  } else {
    teardownAround()
    await reload()
    await nextTick()
    setupFeedObserver()
  }
}

watch(postIdFilter, activate)
watch(() => [artistFilter.value, platformFilter.value, searchFilter.value], async () => {
  if (postIdFilter.value != null) return
  await reload()
  await nextTick()
  setupFeedObserver()
})

onMounted(activate)
onUnmounted(() => { teardownFeed(); teardownAround() })
</script>

<style scoped>
.fc-posts__loading,
.fc-posts__empty {
  display: flex;
  justify-content: center;
  padding: 2rem;
  color: rgb(var(--v-theme-on-surface-variant));
}
.fc-posts__sentinel {
  display: flex;
  justify-content: center;
  padding: 1.5rem 0;
  min-height: 2rem;
}
.fc-posts__end {
  color: rgb(var(--v-theme-on-surface-variant));
  font-size: 0.85rem;
}
.fc-posts__entry--anchor :deep(.fc-post-card) {
  outline: 2px solid rgb(var(--v-theme-accent));
  outline-offset: 3px;
}
</style>
