<template>
  <div class="h-full min-h-0 flex flex-col">
    <AppHeader title="FHIR Explorer" />

    <div class="p-4 sm:p-6 lg:p-8 max-w-6xl mx-auto flex-1 w-full space-y-6">
      <div class="flex flex-wrap items-center justify-between gap-3">
        <h1 class="text-2xl font-bold">FHIR R4 Explorer</h1>
        <button type="button" class="btn-secondary text-sm" @click="openMetadata">
          Open CapabilityStatement (/fhir/metadata)
        </button>
      </div>

      <!-- Resource browser -->
      <div class="card">
        <h2 class="text-lg font-semibold mb-4">Resource Browser</h2>

        <div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4 mb-4">
          <div>
            <label class="block text-sm font-medium text-gray-700 mb-2">Resource Type</label>
            <select v-model="resourceType" class="form-input" @change="clearResults">
              <option value="Patient">Patient</option>
              <option value="Encounter">Encounter</option>
              <option value="Observation">Observation</option>
            </select>
          </div>

          <template v-if="resourceType === 'Patient'">
            <div>
              <label class="block text-sm font-medium text-gray-700 mb-2">Name</label>
              <input v-model="patientSearch.name" type="text" class="form-input" placeholder="e.g. Santos" />
            </div>
            <div>
              <label class="block text-sm font-medium text-gray-700 mb-2">Birth Date</label>
              <input v-model="patientSearch.birthdate" type="date" class="form-input" />
            </div>
            <div>
              <label class="block text-sm font-medium text-gray-700 mb-2">MRN (identifier)</label>
              <input v-model="patientSearch.identifier" type="text" class="form-input" placeholder="VCR-000001" />
            </div>
          </template>

          <template v-else-if="resourceType === 'Encounter'">
            <div>
              <label class="block text-sm font-medium text-gray-700 mb-2">Patient ID</label>
              <input v-model="encounterSearch.patient" type="text" class="form-input" />
            </div>
            <div>
              <label class="block text-sm font-medium text-gray-700 mb-2">Status</label>
              <select v-model="encounterSearch.status" class="form-input">
                <option value="">Any</option>
                <option value="in-progress">in-progress</option>
                <option value="finished">finished</option>
              </select>
            </div>
            <div>
              <label class="block text-sm font-medium text-gray-700 mb-2">Date</label>
              <input v-model="encounterSearch.date" type="date" class="form-input" />
            </div>
          </template>

          <template v-else>
            <div>
              <label class="block text-sm font-medium text-gray-700 mb-2">Patient ID</label>
              <input v-model="observationSearch.patient" type="text" class="form-input" />
            </div>
            <div>
              <label class="block text-sm font-medium text-gray-700 mb-2">LOINC Code</label>
              <input v-model="observationSearch.code" type="text" class="form-input" placeholder="8867-4" />
            </div>
            <div>
              <label class="block text-sm font-medium text-gray-700 mb-2">Category</label>
              <select v-model="observationSearch.category" class="form-input">
                <option value="">Any</option>
                <option value="vital-signs">vital-signs</option>
                <option value="laboratory">laboratory</option>
              </select>
            </div>
            <div>
              <label class="block text-sm font-medium text-gray-700 mb-2">Date (FHIR prefix)</label>
              <input
                v-model="observationSearch.date"
                type="text"
                class="form-input"
                placeholder="ge2026-06-20"
              />
            </div>
          </template>
        </div>

        <button type="button" class="btn-primary" :disabled="searching" @click="runSearch">
          {{ searching ? 'Searching...' : 'Search' }}
        </button>

        <p v-if="searchError" class="text-clinical-danger text-sm mt-3">{{ searchError }}</p>

        <div v-if="searchResults.length > 0" class="mt-6 overflow-x-auto">
          <p class="text-sm text-gray-600 mb-2">
            {{ searchTotal }} result(s)
          </p>
          <table class="min-w-full text-sm border border-gray-200 rounded-md overflow-hidden">
            <thead class="bg-gray-50 text-left">
              <tr>
                <th class="px-3 py-2">ID</th>
                <th v-if="resourceType === 'Patient'" class="px-3 py-2">Name</th>
                <th v-if="resourceType === 'Patient'" class="px-3 py-2">MRN</th>
                <th v-if="resourceType === 'Patient'" class="px-3 py-2">DOB</th>
                <th v-if="resourceType === 'Encounter'" class="px-3 py-2">Status</th>
                <th v-if="resourceType === 'Encounter'" class="px-3 py-2">Patient</th>
                <th v-if="resourceType === 'Observation'" class="px-3 py-2">Code</th>
                <th v-if="resourceType === 'Observation'" class="px-3 py-2">Value</th>
                <th v-if="resourceType === 'Observation'" class="px-3 py-2">Recorded</th>
              </tr>
            </thead>
            <tbody>
              <tr
                v-for="entry in searchResults"
                :key="String(entry.resource?.id)"
                class="border-t border-gray-100 hover:bg-primary-50 cursor-pointer"
                :class="{ 'bg-primary-50': selectedResource?.id === entry.resource?.id }"
                @click="selectResource(entry.resource)"
              >
                <td class="px-3 py-2 font-mono text-xs">{{ entry.resource?.id }}</td>
                <td v-if="resourceType === 'Patient'" class="px-3 py-2">
                  {{ patientDisplayName(entry.resource) }}
                </td>
                <td v-if="resourceType === 'Patient'" class="px-3 py-2">
                  {{ patientMrn(entry.resource) }}
                </td>
                <td v-if="resourceType === 'Patient'" class="px-3 py-2">
                  {{ entry.resource?.birthDate ?? '—' }}
                </td>
                <td v-if="resourceType === 'Encounter'" class="px-3 py-2">
                  {{ entry.resource?.status ?? '—' }}
                </td>
                <td v-if="resourceType === 'Encounter'" class="px-3 py-2">
                  {{ subjectReference(entry.resource) }}
                </td>
                <td v-if="resourceType === 'Observation'" class="px-3 py-2">
                  {{ observationCodeDisplay(entry.resource) }}
                </td>
                <td v-if="resourceType === 'Observation'" class="px-3 py-2">
                  {{ observationValueDisplay(entry.resource) }}
                </td>
                <td v-if="resourceType === 'Observation'" class="px-3 py-2">
                  {{ observationEffective(entry.resource) }}
                </td>
              </tr>
            </tbody>
          </table>
        </div>

        <div v-if="selectedResource" class="mt-6">
          <h3 class="text-sm font-semibold text-gray-700 mb-2">Resource JSON</h3>
          <pre class="bg-gray-900 text-green-100 text-xs p-4 rounded-md overflow-x-auto max-h-96">{{ formattedSelectedResource }}</pre>
        </div>
      </div>

      <!-- Patient $everything -->
      <div class="card">
        <h2 class="text-lg font-semibold mb-4">Patient $everything</h2>
        <p class="text-sm text-gray-600 mb-4">
          Load all FHIR resources for a patient in one Bundle.
        </p>

        <div class="max-w-md mb-4">
          <label class="block text-sm font-medium text-gray-700 mb-2">Patient</label>
          <PatientSearch v-model="everythingPatientId" />
        </div>

        <button
          type="button"
          class="btn-primary"
          :disabled="!everythingPatientId || everythingLoading"
          @click="loadEverything"
        >
          {{ everythingLoading ? 'Loading...' : 'Load All Data' }}
        </button>

        <p v-if="everythingError" class="text-clinical-danger text-sm mt-3">{{ everythingError }}</p>

        <div v-if="everythingBundle" class="mt-6 space-y-6">
          <div v-if="everythingPatient" class="card bg-primary-50 border border-primary-100">
            <h3 class="font-semibold mb-2">Patient</h3>
            <p class="text-sm"><span class="text-gray-500">Name:</span> {{ patientDisplayName(everythingPatient) }}</p>
            <p class="text-sm"><span class="text-gray-500">MRN:</span> {{ patientMrn(everythingPatient) }}</p>
            <p class="text-sm"><span class="text-gray-500">DOB:</span> {{ everythingPatient.birthDate ?? '—' }}</p>
            <p class="text-sm"><span class="text-gray-500">Gender:</span> {{ everythingPatient.gender ?? '—' }}</p>
          </div>

          <div v-if="everythingEncounters.length > 0">
            <h3 class="font-semibold mb-2">Encounters ({{ everythingEncounters.length }})</h3>
            <ul class="space-y-2">
              <li
                v-for="enc in everythingEncounters"
                :key="String(enc.id)"
                class="text-sm border border-gray-200 rounded-md px-3 py-2"
              >
                <span class="font-mono text-xs text-gray-500">{{ enc.id }}</span>
                — {{ enc.status }}
                <span v-if="enc.period?.start"> · {{ enc.period.start }}</span>
              </li>
            </ul>
          </div>

          <div v-if="everythingObservations.length > 0">
            <h3 class="font-semibold mb-2">Observations ({{ everythingObservations.length }})</h3>
            <ul class="space-y-2">
              <li
                v-for="obs in everythingObservations"
                :key="String(obs.id)"
                class="text-sm border border-gray-200 rounded-md px-3 py-2 flex flex-wrap gap-x-3"
              >
                <span class="font-mono text-xs text-gray-500">{{ obs.id }}</span>
                <span>{{ observationCodeDisplay(obs) }}</span>
                <span>{{ observationValueDisplay(obs) }}</span>
                <span class="text-gray-500">{{ observationEffective(obs) }}</span>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, reactive, ref } from 'vue'
import AppHeader from '../components/AppHeader.vue'
import PatientSearch from '../components/PatientSearch.vue'
import {
  fhirGet,
  openFhirJsonInNewTab,
  type FhirBundle,
  type FhirBundleEntry,
  type FhirResource,
} from '../api/fhirClient'

type ResourceType = 'Patient' | 'Encounter' | 'Observation'

const resourceType = ref<ResourceType>('Patient')
const searching = ref(false)
const searchError = ref('')
const searchResults = ref<FhirBundleEntry[]>([])
const searchTotal = ref(0)
const selectedResource = ref<FhirResource | null>(null)

const patientSearch = reactive({ name: '', birthdate: '', identifier: '' })
const encounterSearch = reactive({ patient: '', status: '', date: '' })
const observationSearch = reactive({ patient: '', code: '', category: '', date: '' })

const everythingPatientId = ref<string | undefined>()
const everythingLoading = ref(false)
const everythingError = ref('')
const everythingBundle = ref<FhirBundle | null>(null)

const formattedSelectedResource = computed(() =>
  selectedResource.value ? JSON.stringify(selectedResource.value, null, 2) : ''
)

const everythingPatient = computed(() =>
  everythingBundle.value?.entry
    ?.map((e) => e.resource)
    .find((r) => r?.resourceType === 'Patient') as FhirPatientResource | undefined
)

const everythingEncounters = computed(() =>
  (everythingBundle.value?.entry ?? [])
    .map((e) => e.resource)
    .filter((r): r is FhirEncounterResource => r?.resourceType === 'Encounter')
)

const everythingObservations = computed(() =>
  (everythingBundle.value?.entry ?? [])
    .map((e) => e.resource)
    .filter((r): r is FhirObservationResource => r?.resourceType === 'Observation')
)

type FhirPatientResource = FhirResource & {
  name?: { text?: string; family?: string }[]
  identifier?: { value?: string }[]
  birthDate?: string
  gender?: string
}

type FhirEncounterResource = FhirResource & {
  status?: string
  subject?: { reference?: string }
  period?: { start?: string }
}

type FhirObservationResource = FhirResource & {
  code?: { coding?: { code?: string; display?: string }[]; text?: string }
  valueQuantity?: { value?: number; unit?: string }
  effectiveDateTime?: string
  effective?: string
}

function clearResults(): void {
  searchResults.value = []
  searchTotal.value = 0
  selectedResource.value = null
  searchError.value = ''
}

function selectResource(resource: FhirResource | undefined): void {
  selectedResource.value = resource ?? null
}

function patientDisplayName(resource: FhirResource | undefined): string {
  if (!resource) return '—'
  const patient = resource as FhirPatientResource
  const name = patient.name?.[0]
  return name?.text ?? name?.family ?? '—'
}

function patientMrn(resource: FhirResource | undefined): string {
  if (!resource) return '—'
  const patient = resource as FhirPatientResource
  return patient.identifier?.[0]?.value ?? '—'
}

function subjectReference(resource: FhirResource | undefined): string {
  if (!resource) return '—'
  return (resource as FhirEncounterResource).subject?.reference ?? '—'
}

function observationCodeDisplay(resource: FhirResource | undefined): string {
  if (!resource) return '—'
  const obs = resource as FhirObservationResource
  const coding = obs.code?.coding?.[0]
  return coding?.display ?? coding?.code ?? obs.code?.text ?? '—'
}

function observationValueDisplay(resource: FhirResource | undefined): string {
  if (!resource) return '—'
  const qty = (resource as FhirObservationResource).valueQuantity
  if (!qty) return '—'
  return `${qty.value ?? '—'} ${qty.unit ?? ''}`.trim()
}

function observationEffective(resource: FhirResource | undefined): string {
  if (!resource) return '—'
  const obs = resource as FhirObservationResource
  return obs.effectiveDateTime ?? obs.effective ?? '—'
}

function buildSearchParams(): Record<string, string | number | undefined> {
  if (resourceType.value === 'Patient') {
    return {
      name: patientSearch.name || undefined,
      birthdate: patientSearch.birthdate || undefined,
      identifier: patientSearch.identifier || undefined,
      _count: 20,
    }
  }

  if (resourceType.value === 'Encounter') {
    return {
      patient: encounterSearch.patient || undefined,
      status: encounterSearch.status || undefined,
      date: encounterSearch.date || undefined,
      _count: 20,
    }
  }

  return {
    patient: observationSearch.patient || undefined,
    code: observationSearch.code || undefined,
    category: observationSearch.category || undefined,
    date: observationSearch.date || undefined,
    _count: 50,
  }
}

async function runSearch(): Promise<void> {
  searching.value = true
  searchError.value = ''
  selectedResource.value = null

  try {
    const bundle = await fhirGet<FhirBundle>(`/${resourceType.value}`, buildSearchParams())
    searchResults.value = bundle.entry ?? []
    searchTotal.value = bundle.total ?? searchResults.value.length
  } catch (err: unknown) {
    searchResults.value = []
    searchTotal.value = 0
    searchError.value = err instanceof Error ? err.message : 'FHIR search failed'
  } finally {
    searching.value = false
  }
}

async function loadEverything(): Promise<void> {
  if (!everythingPatientId.value) return

  everythingLoading.value = true
  everythingError.value = ''
  everythingBundle.value = null

  try {
    everythingBundle.value = await fhirGet<FhirBundle>(
      `/Patient/${everythingPatientId.value}/$everything`
    )
  } catch (err: unknown) {
    everythingError.value = err instanceof Error ? err.message : 'Failed to load patient Bundle'
  } finally {
    everythingLoading.value = false
  }
}

async function openMetadata(): Promise<void> {
  try {
    const metadata = await fhirGet('/metadata')
    openFhirJsonInNewTab(metadata, 'capability-statement.json')
  } catch (err: unknown) {
    searchError.value = err instanceof Error ? err.message : 'Failed to load metadata'
  }
}
</script>
