import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { get, post, put, del, patch, uploadFile } from '../api/client'
import type {
  BatchDetailResponse,
  BatchDraft,
  DraftPatient,
  DraftEncounter,
  DraftObservation,
  BatchListResponse,
  FieldCheck,
  PatientDigitizationHistoryResponse,
} from '../types'

function nullIfEmpty(value: string | null | undefined): string | null {
  if (value == null) return null
  const trimmed = value.trim()
  return trimmed === '' ? null : trimmed
}

function parseJsonStringArray(json: string): string[] | null {
  try {
    const parsed = JSON.parse(json)
    return Array.isArray(parsed) ? parsed : null
  } catch {
    return null
  }
}

function toUpsertDraftPatientRequest(
  patient: Partial<DraftPatient> & {
    allergiesJson?: string | null
    medicationsJson?: string | null
  }
): Record<string, unknown> {
  const allergies = Array.isArray(patient.allergies)
    ? patient.allergies
    : patient.allergiesJson
      ? parseJsonStringArray(patient.allergiesJson)
      : null

  const medications = Array.isArray(patient.medications)
    ? patient.medications
    : patient.medicationsJson
      ? parseJsonStringArray(patient.medicationsJson)
      : null

  return {
    fullName: nullIfEmpty(patient.fullName),
    dateOfBirth: nullIfEmpty(patient.dateOfBirth),
    sex: nullIfEmpty(patient.sex),
    bloodType: nullIfEmpty(patient.bloodType),
    emergencyContact: nullIfEmpty(patient.emergencyContact),
    allergies: allergies?.length ? allergies : null,
    noKnownAllergies: patient.noKnownAllergies ?? false,
    medications: medications?.length ? medications : null,
    noActiveMedications: patient.noActiveMedications ?? false,
  }
}

export const useBatchStore = defineStore('batches', () => {
  const batches = ref<BatchDetailResponse[]>([])
  const currentBatch = ref<BatchDetailResponse | null>(null)
  const currentDraft = ref<BatchDraft | null>(null)
  const totalCount = ref(0)
  const loading = ref(false)
  const error = ref<string | null>(null)

  const documentUrl = computed(() => currentBatch.value?.documentUrl ?? null)

  async function listBatches(params: {
    status?: string
    batchType?: string
    assignedTo?: string
    track?: string
    page?: number
    pageSize?: number
  }): Promise<void> {
    loading.value = true
    error.value = null
    try {
      const response = await get<BatchListResponse>(
        'digitization-batches',
        params as Record<string, unknown>
      )
      if (response.success && response.data) {
        batches.value = response.data.items
        totalCount.value = response.data.totalCount
      }
    } catch (e: unknown) {
      error.value = e instanceof Error ? e.message : 'Failed to load batches'
    } finally {
      loading.value = false
    }
  }

  async function getBatch(id: string): Promise<void> {
    loading.value = true
    error.value = null
    try {
      const response = await get<BatchDetailResponse>(
        `digitization-batches/${id}`
      )
      if (response.success && response.data) {
        currentBatch.value = response.data
      }
    } catch (e: unknown) {
      error.value = e instanceof Error ? e.message : 'Failed to load batch'
    } finally {
      loading.value = false
    }
  }

  async function uploadBatch(
    file: File,
    batchType: string,
    track: string,
    patientId?: string,
    supersedesBatchId?: string,
    coverSheetCode?: string,
  ): Promise<BatchDetailResponse | null> {
    loading.value = true
    error.value = null
    try {
      const fields: Record<string, string> = { track }
      if (batchType) fields.batchType = batchType
      if (patientId) fields.patientId = patientId
      if (supersedesBatchId) fields.supersedesBatchId = supersedesBatchId
      if (coverSheetCode) fields.coverSheetCode = coverSheetCode

      const response = await uploadFile<BatchDetailResponse>(
        'digitization-batches',
        file,
        fields
      )
      if (response.success && response.data) {
        return response.data
      }
      return null
    } catch (e: unknown) {
      error.value = e instanceof Error ? e.message : 'Upload failed'
      return null
    } finally {
      loading.value = false
    }
  }

async function assignBatch(batchId: string, entryClerkUserId: string): Promise<void> {
  const response = await patch<BatchDetailResponse>(`digitization-batches/${batchId}/assign`, {
    entryClerkUserId,
  })
  if (!response.success) {
    throw new Error(response.error?.message ?? 'Assignment failed')
  }
}

  async function getDraft(batchId: string): Promise<void> {
    loading.value = true
    try {
      const response = await get<BatchDraft>(
        `digitization-batches/${batchId}/draft`
      )
      if (response.success && response.data) {
        currentDraft.value = response.data
      }
    } finally {
      loading.value = false
    }
  }

  async function saveDraftPatient(
    batchId: string,
    patient: Partial<DraftPatient> & {
      allergiesJson?: string | null
      medicationsJson?: string | null
    }
  ): Promise<void> {
    await put<DraftPatient>(
      `digitization-batches/${batchId}/draft/patient`,
      toUpsertDraftPatientRequest(patient)
    )
  }

  async function saveDraftEncounter(
    batchId: string,
    encounter: Partial<DraftEncounter>
  ): Promise<void> {
    await put<DraftEncounter>(
      `digitization-batches/${batchId}/draft/encounter`,
      encounter
    )
  }

  async function addObservation(
    batchId: string,
    observation: Partial<DraftObservation>
  ): Promise<void> {
    await post<DraftObservation>(
      `digitization-batches/${batchId}/draft/observations`,
      observation
    )
    await getDraft(batchId) // refresh draft to get new observation ID
  }

  async function updateObservation(
    batchId: string,
    obsId: string,
    observation: Partial<DraftObservation>
  ): Promise<void> {
    await put<DraftObservation>(
      `digitization-batches/${batchId}/draft/observations/${obsId}`,
      observation
    )
  }

  async function deleteObservation(batchId: string, obsId: string): Promise<void> {
    await del<void>(`digitization-batches/${batchId}/draft/observations/${obsId}`)
    await getDraft(batchId)
  }

  async function submitForVerification(batchId: string): Promise<void> {
    await post<void>(`digitization-batches/${batchId}/submit-for-verification`)
  }

  async function verifyBatch(
    batchId: string,
    fieldChecks: FieldCheck[],
    passed: boolean
  ): Promise<void> {
    await post<void>(`digitization-batches/${batchId}/verify`, {
      fieldChecks,
      passed,
    })
  }

  async function rejectBatch(batchId: string, reason: string): Promise<void> {
    await post<void>(`digitization-batches/${batchId}/reject`, { reason })
  }

  async function approveBatch(
    batchId: string,
    enableRetroactiveAlerts: boolean = false
  ): Promise<{ status?: number; data?: { mrn: string; encounterId: string; observationIds: string[] } }> {
    const response = await post<{ mrn: string; encounterId: string; observationIds: string[] }>(
      `digitization-batches/${batchId}/approve`,
      { enableRetroactiveAlerts },
      { 'Idempotency-Key': crypto.randomUUID() }
    )
    return { data: response.data ?? undefined }
  }

  async function getPatientHistory(patientId: string): Promise<PatientDigitizationHistoryResponse | null> {
    loading.value = true
    error.value = null
    try {
      const response = await get<PatientDigitizationHistoryResponse>(
        `patients/${patientId}/digitization-history`,
      )
      if (response.success && response.data) {
        return response.data
      }
      return null
    } catch (e: unknown) {
      error.value = e instanceof Error ? e.message : 'Failed to load patient history'
      return null
    } finally {
      loading.value = false
    }
  }

  return {
    batches,
    currentBatch,
    currentDraft,
    documentUrl,
    totalCount,
    loading,
    error,
    listBatches,
    getBatch,
    uploadBatch,
    assignBatch,
    getDraft,
    saveDraftPatient,
    saveDraftEncounter,
    addObservation,
    updateObservation,
    deleteObservation,
    submitForVerification,
    verifyBatch,
    rejectBatch,
    approveBatch,
    getPatientHistory,
  }
})