<!--
  JobThread — fil du billet (osTicket legacy) d'un job, PLUS RÉCENT EN HAUT. Module RÉUTILISABLE extrait du volet jobDetail.
  Autonome : charge via roster.ticketThread(lid) si aucun `thread` n'est fourni. Expose reload() (le parent l'appelle
  après un envoi via JobReplyBox). Repli sur le corps brut si le fil est vide.
-->
<template>
  <div>
    <div class="text-subtitle2 q-mt-md q-mb-xs row items-center">
      Commentaires / fil du billet
      <span v-if="messages.length" class="text-grey-5 q-ml-sm" style="font-size:10px">· plus récent en haut</span>
    </div>
    <div v-if="loading" class="text-center q-pa-md"><q-spinner size="26px" color="primary" /><div class="text-caption text-grey-6 q-mt-sm">Lecture du ticket…</div></div>
    <template v-else-if="messages.length">
      <div class="text-grey-6 q-mb-xs" style="font-size:10px">{{ messages.length }} message(s){{ threadStatus ? ' · ' + threadStatus : '' }}</div>
      <div v-for="(m, mi) in messages" :key="mi" class="de-msg" :class="{ 'de-msg-latest': mi === 0 }">
        <div class="de-msg-hdr">{{ m.author }}<span v-if="m.at" class="text-grey-5"> · {{ fmtDT(m.at) }}</span><span v-if="mi === 0 && messages.length > 1" class="de-msg-badge">dernier</span></div>
        <div class="de-msg-txt">{{ m.text }}</div>
      </div>
    </template>
    <div v-else-if="detail" class="jd-detail">{{ detail }}</div>
    <div v-else class="text-grey-6 q-pa-md text-center">{{ lid ? (loadErr ? 'Détail indisponible' : 'Aucun commentaire.') : 'Pas de billet Legacy lié à ce job.' }}</div>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'
import * as roster from 'src/api/roster'
import { formatDateTime as fmtDT } from 'src/composables/useFormatters'

const props = defineProps({
  lid: { type: [String, Number], default: null }, // n° ticket legacy (osTicket)
  thread: { type: Object, default: null }, // { messages, status } déjà chargé — sinon on fetch
  detail: { type: String, default: '' }, // corps brut de repli (si aucun message)
})

const loaded = ref(null)
const loading = ref(false)
const loadErr = ref(false)
const activeThread = computed(() => props.thread || loaded.value)
const threadStatus = computed(() => (activeThread.value && activeThread.value.status) || '')
// Fil PLUS RÉCENT EN HAUT (le dernier commentaire porte souvent l'info la plus importante).
const messages = computed(() => { const m = (activeThread.value && activeThread.value.messages) || []; return m.slice().reverse() })

async function reload (silent = false) {
  if (props.thread || !props.lid) return
  if (!silent || !loaded.value) { loading.value = true } // silencieux = pas de spinner qui clignote sur le poll
  loadErr.value = false
  try { loaded.value = await roster.ticketThread(props.lid) } catch (e) { if (!silent) { loaded.value = { error: true, messages: [] }; loadErr.value = true } } finally { loading.value = false }
}
watch(() => props.lid, () => { loaded.value = null; reload() })
// Les réponses des techs (app terrain) arrivent PENDANT que le panneau est ouvert → le fil se met à jour tout seul.
let pollTimer = null
onMounted(() => {
  reload()
  pollTimer = setInterval(() => { if (document.visibilityState === 'visible' && !loading.value) reload(true) }, 45000)
})
onBeforeUnmount(() => { if (pollTimer) clearInterval(pollTimer) })
defineExpose({ reload })
</script>

<style scoped>
.de-msg { border-top: 1px solid #e6e0f0; padding: 4px 0; }
.de-msg:first-of-type { border-top: none; }
.de-msg-hdr { font-size: 11px; font-weight: 700; color: #5e35b1; }
.de-msg-txt { font-size: 11px; white-space: pre-wrap; color: #37474f; }
.de-msg-latest { background: #f3f0fb; border-radius: 6px; padding: 6px 8px; margin-bottom: 4px; }
.de-msg-badge { display: inline-block; margin-left: 6px; font-size: 9px; font-weight: 700; color: #fff; background: #7e57c2; border-radius: 4px; padding: 0 5px; vertical-align: middle; }
.jd-detail { margin-top: 10px; padding: 8px 10px; background: #f6f8fb; border-radius: 6px; white-space: pre-wrap; font-size: 12.5px; color: #333; }
</style>
