<template>
  <section v-if="show" class="fc-prov" aria-label="Provenance">
    <h3 class="fc-prov__title">Provenance</h3>

    <v-progress-circular
      v-if="state && state.loading" indeterminate color="accent" size="22"
    />
    <v-alert
      v-else-if="state && state.error" type="error" variant="tonal"
      density="compact"
    >{{ state.error }}</v-alert>

    <!-- Cards scroll independently of the section title + attachments
         below them. Cap at ~2.5 cards visible (operator-asked 2026-06-01:
         keeps the Tags section anchored below at a consistent position;
         the half-visible third card hints there's more). -->
    <div v-else class="fc-prov__cards">
      <article
        v-for="e in state.entries" :key="e.provenance_id" class="fc-prov__card"
      >
        <div class="fc-prov__head">
          <!-- Posts with no live subscription have source=null (alembic
               0030); render an explicit "filesystem import" affordance
               instead of a platform chip. -->
          <span class="fc-prov__platform">
            {{ e.source?.platform ?? 'filesystem import' }}
          </span>
          <span v-if="postDate(e)" class="fc-prov__date">{{ postDate(e) }}</span>
        </div>
        <button
          type="button" class="fc-prov__post"
          :title="`Open ${postTitle(e)} in the posts feed for ${e.artist.name}`"
          @click="openPost(e.post.id, e.artist.id)"
        >
          {{ postTitle(e) }}
        </button>
        <div class="fc-prov__meta">
          <RouterLink :to="`/artist/${e.artist.slug}`">
            by {{ e.artist.name }}
          </RouterLink>
          <span v-if="e.post.attachment_count != null">
            · {{ e.post.attachment_count }} files
          </span>
        </div>
        <div v-if="e.post.description_html" class="fc-prov__actions">
          <a
            href="#" @click.prevent="toggleDesc(e.provenance_id)"
          >{{ expanded[e.provenance_id] ? 'Hide description ▴' : 'Show description ▾' }}</a>
        </div>
        <div
          v-if="e.post.description_html && expanded[e.provenance_id]"
          class="fc-prov__desc" v-html="e.post.description_html"
        />
      </article>

      <!-- Fallback: image has artist_id set (folder-derived from
           filesystem import or set by tag_apply) but no ImageProvenance
           row exists. Show a minimal "by <artist>" line so the modal
           isn't blank for IR-imported images that aren't in any post. -->
      <article
        v-if="showArtistFallback"
        class="fc-prov__card"
      >
        <div class="fc-prov__meta">
          <RouterLink :to="`/artist/${fallbackArtist.slug}`">
            by {{ fallbackArtist.name }}
          </RouterLink>
        </div>
      </article>
    </div>

    <div v-if="attachments.length" class="fc-prov__attach">
      <h4 class="fc-prov__attach-title">Attachments</h4>
      <a
        v-for="at in attachments" :key="at.id"
        class="fc-prov__attach-row"
        :href="at.download_url" :download="at.original_filename"
      >⬇ {{ at.original_filename }}
        <span class="fc-prov__attach-size">({{ at.size_bytes }} B)</span>
      </a>
    </div>
  </section>
</template>

<script setup>
import { computed, reactive, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useModalStore } from '../../stores/modal.js'
import { useProvenanceStore } from '../../stores/provenance.js'
import { formatPostDate } from '../../utils/date.js'
import { toPlainText } from '../../utils/htmlSanitize.js'

const modal = useModalStore()
const prov = useProvenanceStore()
const router = useRouter()

// Per-post description collapse state (keyed by provenance_id). Default
// collapsed so multiple posts don't each eat ~180px of the panel — the
// operator flagged the descriptions consuming a lot of real estate
// 2026-05-28. Reset when the viewed image changes.
const expanded = reactive({})
function toggleDesc(id) { expanded[id] = !expanded[id] }
watch(() => modal.currentImageId, () => {
  for (const k of Object.keys(expanded)) delete expanded[k]
})

watch(
  () => modal.currentImageId,
  (id) => { if (id != null) prov.loadForImage(id) },
  { immediate: true }
)

const state = computed(() =>
  modal.currentImageId == null ? null : prov.imageProv(modal.currentImageId)
)

const fallbackArtist = computed(() => modal.current?.artist || null)

const showArtistFallback = computed(() => {
  const st = state.value
  // Only show the fallback when provenance is genuinely empty (no
  // entries, not loading, no error) AND the image has a direct
  // artist_id we can surface.
  if (!st || st.loading || st.error) return false
  if (Array.isArray(st.entries) && st.entries.length > 0) return false
  return fallbackArtist.value != null
})

// Show the panel while loading or on error, when there is >=1 entry,
// or when the artist fallback applies (image_record.artist_id set but
// no ImageProvenance row, e.g. filesystem-imported IR images).
const show = computed(() => {
  const st = state.value
  if (!st) return false
  if (st.loading || st.error) return true
  if (Array.isArray(st.entries) && st.entries.length > 0) return true
  return showArtistFallback.value
})

const attachments = computed(() => state.value?.attachments || [])

function postDate(e) { return formatPostDate(e.post.date) }
function postTitle(e) {
  // Titles can arrive as stored HTML (e.g. "<strong>…</strong>"); render
  // as plain text (the CSS makes it bold).
  return toPlainText(e.post.title) || `Post ${e.post.external_post_id}`
}

function openPost(postId, artistId) {
  // Land on the post in the posts feed (in context), not the gallery
  // image grid. Scope the feed to this artist so the user lands in
  // that creator's stream, not the global one — operator-flagged
  // 2026-06-01. PostsView reads `artist_id` from the query string
  // (PostsView.vue line ~92) and filters via post_feed_service.
  router.push({
    path: '/posts',
    query: { post_id: postId, artist_id: artistId },
  })
  modal.close()
}
</script>

<style scoped>
.fc-prov { padding: 16px 16px 0; }
.fc-prov__title {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 18px; font-weight: 500;
  color: rgb(var(--v-theme-on-surface));
  margin-bottom: 12px;
}
.fc-prov__cards {
  /* 2.5 cards-worth at the typical collapsed card height (~108px each
     incl. 10px gap). Slightly under to ensure the third card's bottom
     edge is clipped — the visual cue that there's more below. */
  max-height: 270px;
  overflow-y: auto;
  /* Hairline scrollbar that doesn't compete with content. */
  scrollbar-width: thin;
  scrollbar-color: rgb(var(--v-theme-surface-light)) transparent;
  /* Pad-right so the scrollbar gutter doesn't squeeze card borders. */
  padding-right: 4px;
}
.fc-prov__card {
  border: 1px solid rgb(var(--v-theme-surface-light));
  border-radius: 6px; padding: 10px 12px; margin-bottom: 10px;
}
.fc-prov__head {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 12px; color: rgb(var(--v-theme-on-surface-variant));
  text-transform: lowercase;
}
.fc-prov__post {
  /* Clickable title — opens the post in the artist-scoped feed
     (operator-flagged 2026-06-01: title IS the primary action, the
     prior "View post" link was redundant). Styled as a button-link:
     accent color, underline on hover, focus ring for keyboard nav. */
  display: block; width: 100%; text-align: left;
  background: none; border: none; padding: 0;
  font: inherit; font-weight: 700;
  margin: 4px 0;
  color: rgb(var(--v-theme-accent));
  cursor: pointer;
}
.fc-prov__post:hover { text-decoration: underline; }
.fc-prov__post:focus-visible {
  outline: 2px solid rgb(var(--v-theme-accent));
  outline-offset: 2px; border-radius: 3px;
}
.fc-prov__meta {
  font-size: 13px; color: rgb(var(--v-theme-on-surface-variant));
  display: flex; gap: 6px; flex-wrap: wrap;
}
.fc-prov__meta a { color: rgb(var(--v-theme-accent)); text-decoration: none; }
.fc-prov__actions {
  display: flex; gap: 12px; flex-wrap: wrap;
  margin-top: 6px; font-size: 13px;
}
.fc-prov__actions a {
  color: rgb(var(--v-theme-accent)); text-decoration: none;
}
.fc-prov__desc {
  margin-top: 8px; font-size: 13px; line-height: 1.5;
  max-height: 180px; overflow: auto;
  color: rgb(var(--v-theme-on-surface-variant));
}
.fc-prov__desc :deep(a) { color: rgb(var(--v-theme-accent)); }
.fc-prov__attach { padding: 0 0 12px; }
.fc-prov__attach-title {
  font-size: 13px; color: rgb(var(--v-theme-on-surface-variant));
  margin: 8px 0 4px;
}
.fc-prov__attach-row {
  display: block; font-size: 13px; text-decoration: none;
  color: rgb(var(--v-theme-accent)); padding: 2px 0;
}
.fc-prov__attach-size { color: rgb(var(--v-theme-on-surface-variant)); }
</style>
