<script setup>
import { ref, watch, computed, onBeforeUnmount } from 'vue'
import { useRoute } from 'vue-router'
import { storeToRefs } from 'pinia'
import { usePolling } from '@/composables/usePolling'
import { useReplayControls } from '@/composables/useReplayControls'
import { useRoleAccess } from '@/composables/roleAccess'
import { useAlertStore } from '@/stores/alerts'
import { useScoringStore } from '@/stores/scoring'
import * as encountersApi from '@/api/encounters'
import * as clinicalApi from '@/api/clinical'
import * as alertsApi from '@/api/alerts'
import PatientBanner from '@/components/patient/PatientBanner.vue'
import VitalsPanel from '@/components/patient/VitalsPanel.vue'
import ScoresPanel from '@/components/patient/ScoresPanel.vue'
import SofaScorePanel from '@/components/patient/SofaScorePanel.vue'
import AlertsList from '@/components/patient/AlertsList.vue'
import OrdersPanel from '@/components/patient/OrdersPanel.vue'
import SepsisBundlePanel from '@/components/patient/SepsisBundlePanel.vue'
import TrendsGrid from '@/components/charts/TrendsGrid.vue'
import News2History from '@/components/charts/News2History.vue'
import GcsHistory from '@/components/charts/GcsHistory.vue'
import QsofaHistory from '@/components/charts/QsofaHistory.vue'
import SofaHistory from '@/components/charts/SofaHistory.vue'
import EncounterTimeline from '@/components/patient/EncounterTimeline.vue'
import DischargeSummaryPanel from '@/components/patient/DischargeSummaryPanel.vue'
import ReplayControls from '@/components/replay/ReplayControls.vue'
import AlertReasoning from '@/components/alerts/AlertReasoning.vue'
import CollapsibleSection from '@/components/ui/CollapsibleSection.vue'
import Skeleton from '@/components/ui/Skeleton.vue'

const route = useRoute()
const { nursePatientLayout, physicianPatientLayout } = useRoleAccess()
const alertStore = useAlertStore()
const scoringStore = useScoringStore()
const { alerts } = storeToRefs(alertStore)
const { qsofa, sofa } = storeToRefs(scoringStore)
const {
  isPaused,
  speed,
  progress,
  formattedTime,
  currentMs,
  scenarioEndMs,
  scenarioStartMs,
  pause,
  resume,
  setSpeed,
  jumpToTimestamp,
  isAtOrBefore,
  setScenarioBounds,
  syncToEnd,
  stopPlayback,
} = useReplayControls()

const encounter = ref(null)
const loading = ref(true)
const observations = ref([])
const news2History = ref([])
const gcsHistory = ref([])
const qsofaHistory = ref([])
const sofaHistory = ref([])
const medications = ref([])
const sepsisBundle = ref(null)
const orders = ref([])
const timelineEvents = ref([])
const selectedAlert = ref(null)
let nextAlertIndex = 0

const openAlerts = computed(() =>
  alerts.value.filter(a => a.status === 'OPEN' || a.status === 'ESCALATED'),
)

const isDischarged = computed(() => encounter.value?.status === 'Discharged')

const replayObservations = computed(() =>
  observations.value.filter(o => isAtOrBefore(o.recordedAt)),
)

const replayMedications = computed(() =>
  medications.value.filter(m => isAtOrBefore(m.administeredAt)),
)

const replayNews2History = computed(() =>
  news2History.value.filter(h => isAtOrBefore(h.calculatedAt)),
)

const replayGcsHistory = computed(() =>
  gcsHistory.value.filter(h => isAtOrBefore(h.calculatedAt)),
)

const replayQsofaHistory = computed(() =>
  qsofaHistory.value.filter(h => isAtOrBefore(h.evaluatedAt)),
)

const replaySofaHistory = computed(() =>
  sofaHistory.value.filter(h => isAtOrBefore(h.calculatedAt)),
)

const replayTimelineEvents = computed(() =>
  timelineEvents.value.filter(e => isAtOrBefore(e.timestamp)),
)

function collectScenarioTimes() {
  return [
    ...observations.value.map(o => new Date(o.recordedAt).getTime()),
    ...news2History.value.map(h => new Date(h.calculatedAt).getTime()),
    ...gcsHistory.value.map(h => new Date(h.calculatedAt).getTime()),
    ...qsofaHistory.value.map(h => new Date(h.evaluatedAt).getTime()),
    ...sofaHistory.value.map(h => new Date(h.calculatedAt).getTime()),
    ...timelineEvents.value.map(e => new Date(e.timestamp).getTime()),
    ...alerts.value.map(a => new Date(a.triggeredAt).getTime()),
  ].filter(Number.isFinite)
}

function syncReplayBounds() {
  const times = collectScenarioTimes()
  if (!times.length) return

  const atEnd = currentMs.value >= scenarioEndMs.value - 1_000
  setScenarioBounds(Math.min(...times), Math.max(...times))
  if (atEnd || scenarioEndMs.value === scenarioStartMs.value) {
    syncToEnd()
  }
}

async function loadAll() {
  const id = route.params.encounterId
  loading.value = true
  try {
    const [enc, obs, history, gcsHist, qsofaHist, sofaHist, meds, bundle, ord, timeline] = await Promise.all([
      encountersApi.fetchEncounter(id),
      encountersApi.fetchObservations(id),
      clinicalApi.fetchNews2History(id).catch(() => []),
      clinicalApi.fetchGcsHistory(id).catch(() => []),
      clinicalApi.fetchQsofaHistory(id).catch(() => []),
      clinicalApi.fetchSofaHistory(id).catch(() => []),
      clinicalApi.fetchMedications(id).catch(() => []),
      clinicalApi.fetchSepsisBundle(id),
      clinicalApi.fetchOrders(id).catch(() => ({ items: [] })),
      encountersApi.fetchTimeline(id).catch(() => ({ events: [] })),
    ])
    await alertStore.loadAlerts(id)
    encounter.value = enc
    observations.value = obs
    news2History.value = history
    gcsHistory.value = gcsHist
    qsofaHistory.value = qsofaHist
    sofaHistory.value = sofaHist
    medications.value = meds
    sepsisBundle.value = bundle
    orders.value = ord.items ?? ord
    timelineEvents.value = timeline.events ?? []
    scoringStore.startPolling(id)
    syncReplayBounds()
  } finally {
    loading.value = false
  }
}

async function onSelectAlert(alert) {
  try {
    selectedAlert.value = await alertsApi.fetchAlertById(alert.id)
  } catch {
    selectedAlert.value = alert
  }
  jumpToTimestamp(alert.triggeredAt)
}

function jumpToNextAlert() {
  const sorted = [...openAlerts.value].sort(
    (a, b) => new Date(a.triggeredAt) - new Date(b.triggeredAt),
  )
  if (!sorted.length) return

  const alert = sorted[nextAlertIndex % sorted.length]
  selectedAlert.value = alert
  nextAlertIndex++
  jumpToTimestamp(alert.triggeredAt)

  document.getElementById(`alert-row-${alert.id}`)?.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
  document.getElementById('clinical-review')?.scrollIntoView({ behavior: 'smooth', block: 'start' })
}

usePolling(loadAll, 5_000)

watch(() => route.params.encounterId, () => {
  selectedAlert.value = null
  nextAlertIndex = 0
  pause()
  scoringStore.stopPolling()
  loadAll()
})

watch(openAlerts, (list) => {
  nextAlertIndex = 0
  if (selectedAlert.value && !list.some(a => a.id === selectedAlert.value.id)) {
    selectedAlert.value = null
  }
})

watch([observations, news2History, gcsHistory, qsofaHistory, sofaHistory, timelineEvents, alerts], syncReplayBounds, { deep: true })

onBeforeUnmount(() => {
  stopPlayback()
  scoringStore.stopPolling()
})
</script>

<template>
  <Skeleton v-if="loading && !encounter" :rows="6" />
  <div v-else-if="encounter" class="w-full min-w-0 space-y-6 lg:space-y-8">
    <div class="flex flex-wrap items-center gap-4">
      <RouterLink
        to="/ward"
        class="inline-flex min-h-11 items-center text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
      >
        &larr; Ward
      </RouterLink>
    </div>

    <PatientBanner :encounter="encounter" />

    <DischargeSummaryPanel
      :encounter-id="route.params.encounterId"
      :discharged="isDischarged"
    />

    <div class="flex flex-col gap-4 lg:grid lg:grid-cols-3">
      <div
        class="order-1 space-y-4"
        :class="{
          'lg:order-3': nursePatientLayout,
          'lg:order-1': physicianPatientLayout || (!nursePatientLayout && !physicianPatientLayout),
        }"
      >
        <ScoresPanel />
        <GcsHistory v-if="replayGcsHistory.length" :history="replayGcsHistory" />
      </div>
      <VitalsPanel
        class="order-2 min-w-0 lg:order-2"
        :encounter-id="route.params.encounterId"
        :observations="replayObservations"
        @recorded="loadAll"
      />
      <AlertsList
        class="order-3 min-w-0 lg:order-3"
        :class="{ 'lg:order-1': nursePatientLayout }"
        :encounter-id="route.params.encounterId"
        :selected-id="selectedAlert?.id"
        @select="onSelectAlert"
      />
    </div>

    <AlertReasoning
      v-if="selectedAlert"
      :alert="selectedAlert"
      :medications="medications"
    />

    <div class="flex flex-col gap-4 lg:grid lg:grid-cols-2">
      <div class="order-2 space-y-4 lg:order-1">
        <SofaScorePanel :encounter-id="route.params.encounterId" />
        <SofaHistory v-if="replaySofaHistory.length" :history="replaySofaHistory" />
      </div>
      <div class="order-1 lg:order-2">
        <OrdersPanel :orders="orders" />
      </div>
    </div>

    <SepsisBundlePanel
      :bundle="sepsisBundle"
      :qsofa="qsofa"
      :sofa="sofa"
    />

    <div class="hidden lg:block">
      <EncounterTimeline :events="replayTimelineEvents" />
    </div>
    <CollapsibleSection
      class="lg:hidden"
      section-id="encounter-timeline"
      title="Encounter timeline"
      :default-open="false"
    >
      <EncounterTimeline :events="replayTimelineEvents" />
    </CollapsibleSection>

    <div id="clinical-review" class="hidden w-full min-w-0 space-y-6 lg:block lg:space-y-8">
      <TrendsGrid :observations="replayObservations" :medications="replayMedications" />
      <News2History v-if="replayNews2History.length" :history="replayNews2History" />
      <QsofaHistory v-if="replayQsofaHistory.length" :history="replayQsofaHistory" />
      <ReplayControls
        :alerts="openAlerts"
        :is-paused="isPaused"
        :progress="progress"
        :formatted-time="formattedTime"
        :speed="speed"
        @pause="pause()"
        @resume="resume()"
        @set-speed="setSpeed"
        @jump-to-alert="jumpToNextAlert"
      />
    </div>

    <CollapsibleSection
      class="lg:hidden"
      section-id="clinical-review"
      title="Vital trends & clinical review"
      :default-open="false"
    >
      <div class="space-y-6">
        <TrendsGrid :observations="replayObservations" :medications="replayMedications" />
        <News2History v-if="replayNews2History.length" :history="replayNews2History" />
        <QsofaHistory v-if="replayQsofaHistory.length" :history="replayQsofaHistory" />
      </div>
    </CollapsibleSection>

    <CollapsibleSection
      class="lg:hidden"
      section-id="replay-controls"
      title="Scenario replay"
      :default-open="false"
    >
      <ReplayControls
        :alerts="openAlerts"
        :is-paused="isPaused"
        :progress="progress"
        :formatted-time="formattedTime"
        :speed="speed"
        @pause="pause()"
        @resume="resume()"
        @set-speed="setSpeed"
        @jump-to-alert="jumpToNextAlert"
      />
    </CollapsibleSection>
  </div>
</template>