<template>
  <div
    class="h-full min-h-0 flex flex-col approval-frame"
    data-testid="approval-form"
  >
    <div class="flex-1 min-h-0 overflow-y-auto p-4 space-y-4">
      <div class="flex items-start justify-between gap-3">
        <div>
          <p class="evidence-level evidence-level--2 mb-1">
            <span class="evidence-level-mark" aria-hidden="true">2</span>
            Verified draft
          </p>
          <h2 class="text-base font-semibold text-ink-strong">Clinical Approval</h2>
          <p class="mt-1 text-xs text-ink-secondary max-w-md">
            Clinical sign-off before promotion to live clinical tables. Review the source scan and verified draft.
          </p>
        </div>
        <StatusBadge :status="batch?.status ?? 'AWAITING_CLINICAL_APPROVAL'" />
      </div>

      <div
        v-if="batch?.supersedesBatchId"
        class="rounded-input border border-primary-100 bg-primary-50 p-3 text-sm"
      >
        <p class="font-medium text-primary-800">Correction Batch</p>
        <p class="text-primary-700 mt-1">
          This batch corrects and will supersede batch
          <span class="font-mono">{{ batch.supersedesBatchId.substring(0, 8) }}...</span>
        </p>
        <button
          v-if="batch.patientId"
          type="button"
          class="text-xs text-primary-600 hover:text-primary-800 mt-2"
          @click="$emit('view-history', batch.patientId)"
        >
          View patient history
        </button>
      </div>

      <!-- High-stakes clinical signals (design-doc §16) -->
      <section
        v-if="highStakeItems.length > 0"
        class="rounded-input border border-[#FEDF89] bg-clinical-warning-bg/60 p-3"
        data-testid="high-stakes-summary"
      >
        <p class="evidence-level evidence-level--4 mb-2 !text-clinical-warning">
          <span class="evidence-level-mark" aria-hidden="true">!</span>
          High-stakes clinical signals
        </p>
        <ul class="space-y-2">
          <li
            v-for="item in highStakeItems"
            :key="item.key"
            class="clinical-signal"
            :class="{ 'clinical-signal--critical': item.critical }"
          >
            <span class="text-xs font-semibold uppercase tracking-wide text-ink-secondary">
              {{ item.label }}
            </span>
            <p class="font-medium text-ink-strong mt-0.5">{{ item.value }}</p>
            <p v-if="item.reason" class="text-xs text-ink-secondary mt-0.5">{{ item.reason }}</p>
          </li>
        </ul>
      </section>

      <fieldset v-if="draft?.patient" class="workstation-form-section">
        <legend class="workstation-form-legend">Patient</legend>
        <div class="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
          <div>
            <span class="text-ink-secondary">Full Name</span>
            <p class="font-medium text-ink-strong">{{ draft.patient.fullName || '—' }}</p>
          </div>
          <div>
            <span class="text-ink-secondary">DOB</span>
            <p class="font-medium text-ink-strong">{{ draft.patient.dateOfBirth ?? 'N/A' }}</p>
          </div>
          <div>
            <span class="text-ink-secondary">Sex</span>
            <p class="font-medium text-ink-strong">{{ draft.patient.sex ?? 'N/A' }}</p>
          </div>
          <div :class="draft.patient.bloodType ? 'rounded-input bg-clinical-warning-bg/50 px-2 py-1 -mx-2' : ''">
            <span class="text-ink-secondary">Blood Type</span>
            <p class="font-medium text-ink-strong">{{ draft.patient.bloodType ?? 'N/A' }}</p>
          </div>
        </div>
      </fieldset>

      <fieldset v-if="draft?.encounter" class="workstation-form-section">
        <legend class="workstation-form-legend">Encounter</legend>
        <div class="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
          <div>
            <span class="text-ink-secondary">Admission</span>
            <p class="font-medium text-ink-strong">{{ draft.encounter.admissionDate ?? 'N/A' }}</p>
          </div>
          <div>
            <span class="text-ink-secondary">Department</span>
            <p class="font-medium text-ink-strong">{{ draft.encounter.department ?? 'N/A' }}</p>
          </div>
          <div>
            <span class="text-ink-secondary">Room / Bed</span>
            <p class="font-medium text-ink-strong">{{ draft.encounter.roomBed ?? 'N/A' }}</p>
          </div>
          <div>
            <span class="text-ink-secondary">Reason</span>
            <p class="font-medium text-ink-strong">{{ draft.encounter.admissionReason ?? 'N/A' }}</p>
          </div>
        </div>
      </fieldset>

      <fieldset class="workstation-form-section">
        <legend class="workstation-form-legend">
          Observations ({{ draft?.observations?.length ?? 0 }})
        </legend>
        <div class="space-y-2">
          <ObservationRow
            v-for="obs in (draft?.observations ?? [])"
            :key="obs.id"
            :observation="obs"
            :readonly="true"
          />
          <p v-if="!draft?.observations?.length" class="text-sm text-ink-secondary">
            No observations recorded.
          </p>
        </div>
      </fieldset>

      <div
        v-if="batch?.verifiedByUserId"
        class="rounded-input border border-line bg-canvas px-3 py-2 text-sm text-ink-secondary"
      >
        <span class="text-xs uppercase tracking-wide font-semibold">Verified by</span>
        <p class="font-mono text-ink mt-0.5">{{ batch.verifiedByUserId.substring(0, 8) }}…</p>
      </div>

      <!-- Level 4 decision controls (copy weight below draft) -->
      <section
        class="rounded-input border border-line bg-canvas p-3 space-y-3"
        data-testid="approval-decision"
      >
        <p class="evidence-level evidence-level--4 mb-0">
          <span class="evidence-level-mark" aria-hidden="true">4</span>
          Clinical decision
        </p>
        <label class="flex items-start gap-3 cursor-pointer">
          <input
            v-model="enableRetroactiveAlerts"
            type="checkbox"
            class="mt-1 w-4 h-4 text-clinical-safe rounded"
            data-testid="retroactive-alerts"
          />
          <div>
            <span class="text-sm font-medium text-ink-strong">
              Run alert evaluation after promotion
            </span>
            <p class="text-xs text-ink-secondary mt-0.5">
              May generate alerts for clinical criteria represented in historical records.
              It should not sound like alerts occurred contemporaneously.
            </p>
          </div>
        </label>
      </section>

      <!-- Level 5 promotion outcome -->
      <section
        v-if="promotionResult"
        class="promotion-outcome"
        data-testid="promotion-result"
      >
        <p class="evidence-level evidence-level--5 mb-2">
          <span class="evidence-level-mark" aria-hidden="true">5</span>
          Promotion outcome
        </p>
        <p class="font-semibold text-clinical-safe">Promoted to live clinical tables</p>
        <dl class="mt-3 grid gap-2 sm:grid-cols-3 text-sm">
          <div>
            <dt class="text-xs text-ink-secondary uppercase tracking-wide">Patient MRN</dt>
            <dd class="font-mono font-medium text-ink-strong mt-0.5">{{ promotionResult.mrn }}</dd>
          </div>
          <div>
            <dt class="text-xs text-ink-secondary uppercase tracking-wide">Encounter</dt>
            <dd class="font-mono font-medium text-ink-strong mt-0.5">
              {{ promotionResult.encounterId?.substring(0, 8) }}…
            </dd>
          </div>
          <div>
            <dt class="text-xs text-ink-secondary uppercase tracking-wide">Observations</dt>
            <dd class="font-medium text-ink-strong mt-0.5">
              {{ promotionResult.observationIds?.length ?? 0 }} promoted
            </dd>
          </div>
        </dl>
        <div class="flex flex-wrap gap-4 mt-3 pt-3 border-t border-[#ABEFC6]">
          <button
            type="button"
            class="text-sm text-primary-600 hover:text-primary-800 font-medium"
            @click="$emit('create-correction')"
          >
            Create Correction
          </button>
          <button
            v-if="batch?.patientId"
            type="button"
            class="text-sm text-ink-secondary hover:text-ink-strong"
            @click="$emit('view-history', batch.patientId)"
          >
            View Patient History
          </button>
        </div>
      </section>

      <div
        v-if="deferred"
        class="rounded-input border border-[#FEDF89] bg-clinical-warning-bg p-4 text-sm"
        data-testid="promotion-deferred"
      >
        <p class="font-medium text-clinical-warning">Approved — Promotion Deferred</p>
        <p class="text-ink mt-1">
          Promotion will be retried automatically due to a temporary infrastructure issue.
        </p>
      </div>

      <div v-if="errorMessage" class="text-clinical-danger text-sm" role="alert">
        {{ errorMessage }}
      </div>

      <AuditTrailPanel :batch-id="batchId" />
    </div>

    <WorkstationActionBar>
      <template #left>
        <button
          type="button"
          class="btn-danger"
          :disabled="processing || !!promotionResult"
          data-testid="reject-batch"
          @click="showRejectDialog = true"
        >
          Reject Batch
        </button>
      </template>
      <template #primary>
        <button
          type="button"
          class="btn-primary"
          :disabled="processing || !!promotionResult"
          data-testid="approve-promote"
          @click="showApproveConfirm = true"
        >
          {{ processing ? 'Promoting...' : 'Approve & Promote' }}
        </button>
      </template>
      <template #right>
        <button
          type="button"
          class="btn-secondary"
          :disabled="processing"
          @click="$emit('back')"
        >
          Back to Queue
        </button>
      </template>
    </WorkstationActionBar>

    <ConfirmDialog
      :open="showApproveConfirm"
      title="Approve & Promote"
      body="Approval will promote the verified records into live clinical tables."
      confirm-label="Approve & Promote"
      variant="primary"
      :confirm-disabled="processing"
      @confirm="confirmApprove"
      @cancel="showApproveConfirm = false"
    />

    <ConfirmDialog
      :open="showRejectDialog"
      title="Reject Batch"
      body="This returns the batch for rework. A reason is required."
      confirm-label="Reject Batch"
      variant="danger"
      :confirm-disabled="!rejectionReason.trim() || processing"
      @confirm="reject"
      @cancel="closeRejectDialog"
    >
      <textarea
        v-model="rejectionReason"
        class="form-input"
        rows="4"
        placeholder="Reason for rejection (required)..."
      />
    </ConfirmDialog>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useBatchStore } from '../stores/batches'
import { useToast } from '../composables/useToast'
import ObservationRow from './ObservationRow.vue'
import StatusBadge from './StatusBadge.vue'
import ConfirmDialog from './ConfirmDialog.vue'
import AuditTrailPanel from './AuditTrailPanel.vue'
import WorkstationActionBar from './WorkstationActionBar.vue'
import type { BatchDetailResponse, BatchDraft, DraftObservation } from '../types'

const props = defineProps<{
  batch: BatchDetailResponse | null
  batchId: string
  draft: BatchDraft | null
}>()

const emit = defineEmits<{
  (e: 'back'): void
  (e: 'view-history', patientId: string): void
  (e: 'create-correction'): void
  (e: 'approved'): void
  (e: 'rejected'): void
}>()

const batchStore = useBatchStore()
const toast = useToast()

const processing = ref(false)
const errorMessage = ref('')
const enableRetroactiveAlerts = ref(false)
const showApproveConfirm = ref(false)
const showRejectDialog = ref(false)
const rejectionReason = ref('')
const promotionResult = ref<{ mrn: string; encounterId: string; observationIds: string[] } | null>(null)
const deferred = ref(false)

watch(
  () => props.batchId,
  () => {
    promotionResult.value = null
    deferred.value = false
    errorMessage.value = ''
    enableRetroactiveAlerts.value = false
    rejectionReason.value = ''
  }
)

interface HighStakeItem {
  key: string
  label: string
  value: string
  reason?: string
  critical?: boolean
}

function isCriticalObservation(obs: DraftObservation): boolean {
  const code = (obs.observationCode ?? '').toUpperCase()
  const value = Number(obs.value)
  if (Number.isNaN(value)) return false
  if (code.includes('TEMP') && value >= 38) return true
  if (code.includes('SPO2') && value < 92) return true
  if ((code.includes('HEART') || code === 'HR') && (value > 120 || value < 40)) return true
  if (code.includes('BP_SYSTOLIC') && (value >= 180 || value < 90)) return true
  if (code.includes('LACTATE') && value >= 2) return true
  if (code.includes('POTASSIUM') && (value < 3 || value > 5.5)) return true
  return false
}

function formatObsLabel(code: string): string {
  return code.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase())
}

const highStakeItems = computed((): HighStakeItem[] => {
  const draft = props.draft
  if (!draft) return []
  const items: HighStakeItem[] = []
  const patient = draft.patient

  if (patient?.bloodType) {
    items.push({
      key: 'bloodType',
      label: 'Blood type',
      value: patient.bloodType,
      reason: 'High-stakes demographic for transfusion safety',
    })
  }

  if (patient?.noKnownAllergies) {
    items.push({
      key: 'nka',
      label: 'Allergies',
      value: 'No known allergies (NKA)',
    })
  } else if (patient?.allergies?.length) {
    items.push({
      key: 'allergies',
      label: 'Allergies',
      value: patient.allergies.join(', '),
      reason: 'Allergy documentation requires clinical oversight',
      critical: true,
    })
  }

  if (patient?.noActiveMedications) {
    items.push({
      key: 'nam',
      label: 'Medications',
      value: 'No active medications',
    })
  } else if (patient?.medications?.length) {
    items.push({
      key: 'medications',
      label: 'Medications',
      value: patient.medications.join(', '),
      reason: 'Medication list requires clinical oversight',
      critical: true,
    })
  }

  for (const obs of draft.observations ?? []) {
    if (!isCriticalObservation(obs)) continue
    items.push({
      key: `obs-${obs.id}`,
      label: formatObsLabel(obs.observationCode),
      value: `${obs.value}${obs.unit ? ` ${obs.unit}` : ''}`,
      reason: 'Out-of-range clinical signal',
      critical: true,
    })
  }

  return items
})

function closeRejectDialog() {
  showRejectDialog.value = false
}

async function confirmApprove() {
  showApproveConfirm.value = false
  await approve()
}

async function approve() {
  processing.value = true
  errorMessage.value = ''
  promotionResult.value = null
  deferred.value = false

  try {
    const response = await batchStore.approveBatch(props.batchId, enableRetroactiveAlerts.value)
    if (response?.status === 202) {
      deferred.value = true
      toast.info('Approved. Promotion will be retried automatically.')
    } else if (response?.data) {
      promotionResult.value = response.data
      toast.success('Batch approved and promoted successfully')
      emit('approved')
    }
  } catch (e: unknown) {
    const msg = e instanceof Error ? e.message : 'Approval failed'
    if (msg.includes('PROMOTION_DEFERRED')) {
      deferred.value = true
      toast.info('Approved. Promotion will be retried automatically.')
    } else {
      errorMessage.value = msg
      toast.error(msg)
    }
  } finally {
    processing.value = false
  }
}

async function reject() {
  processing.value = true
  errorMessage.value = ''
  try {
    await batchStore.rejectBatch(props.batchId, rejectionReason.value)
    showRejectDialog.value = false
    toast.warning('Batch rejected')
    emit('rejected')
  } catch (e: unknown) {
    const msg = e instanceof Error ? e.message : 'Rejection failed'
    errorMessage.value = msg
    toast.error(msg)
  } finally {
    processing.value = false
  }
}
</script>
