import { describe, it, expect, vi, beforeEach } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import { setActivePinia, createPinia } from 'pinia'
import EntryForm from '@/components/EntryForm.vue'
import { useBatchStore } from '@/stores/batches'
import type { BatchDetailResponse } from '@/types'
import {
  emptyDraft,
  fieldRequirementsForBatchType,
} from '@/__tests__/helpers/fieldRequirements'

vi.mock('@/api/client', () => ({
  get: vi.fn(),
  post: vi.fn(),
  put: vi.fn(),
  del: vi.fn(),
  patch: vi.fn(),
  uploadFile: vi.fn(),
}))

vi.mock('@/composables/useToast', () => ({
  useToast: () => ({
    success: vi.fn(),
    error: vi.fn(),
    warning: vi.fn(),
    info: vi.fn(),
  }),
}))

function makeBatch(overrides: Partial<BatchDetailResponse> = {}): BatchDetailResponse {
  const batchType = overrides.batchType ?? 'VITALS'
  return {
    id: 'b1',
    status: 'IN_ENTRY',
    batchType,
    track: 'TRACK_A',
    fieldRequirements: fieldRequirementsForBatchType(batchType),
    patientId: null,
    documentRef: 'docs/scan.pdf',
    documentUrl: null,
    enableRetroactiveAlerts: false,
    enteredByUserId: 'u1',
    verifiedByUserId: null,
    approvedByUserId: null,
    rejectionReason: null,
    promotedAt: null,
    promotionEncounterId: null,
    supersedesBatchId: null,
    clinicianAttestation: false,
    isCorrection: false,
    supersession: null,
    createdAt: '2026-06-27T10:00:00Z',
    updatedAt: '2026-06-27T10:00:00Z',
    ...overrides,
  }
}

function mountWithDraft(
  batchOverrides: Partial<BatchDetailResponse> = {},
) {
  const batch = makeBatch(batchOverrides)
  const store = useBatchStore()
  store.currentDraft = emptyDraft(batch.batchType)
  return mount(EntryForm, {
    props: { batch, batchId: 'b1' },
  })
}

beforeEach(() => {
  setActivePinia(createPinia())
  vi.clearAllMocks()
})

describe('EntryForm', () => {
  it('renders patient demographics fields', () => {
    const wrapper = mount(EntryForm, {
      props: { batch: makeBatch(), batchId: 'b1' },
    })
    expect(wrapper.text()).toContain('Patient Demographics')
    expect(wrapper.text()).toContain('Full Name')
    expect(wrapper.text()).toContain('Date of Birth')
    expect(wrapper.text()).toContain('Sex')
    expect(wrapper.text()).toContain('Blood Type')
    expect(wrapper.text()).toContain('Emergency Contact')
  })

  it('renders encounter context fields', () => {
    const wrapper = mount(EntryForm, {
      props: { batch: makeBatch(), batchId: 'b1' },
    })
    expect(wrapper.text()).toContain('Encounter Context')
    expect(wrapper.text()).toContain('Admission Date')
    expect(wrapper.text()).toContain('Department')
    expect(wrapper.text()).toContain('Room / Bed')
    expect(wrapper.text()).toContain('Admission Reason')
  })

  it('renders observations section with add button', () => {
    const wrapper = mount(EntryForm, {
      props: { batch: makeBatch(), batchId: 'b1' },
    })
    expect(wrapper.text()).toContain('Observations')
    expect(wrapper.text()).toContain('+ Add Observation')
  })

  it('renders submit button', () => {
    const wrapper = mount(EntryForm, {
      props: { batch: makeBatch(), batchId: 'b1' },
    })
    const buttons = wrapper.findAll('button')
    const submitButton = buttons.find((b) => b.text().includes('Submit for Verification'))
    expect(submitButton).toBeTruthy()
  })

  it('displays batch status', () => {
    const wrapper = mount(EntryForm, {
      props: { batch: makeBatch({ status: 'IN_ENTRY' }), batchId: 'b1' },
    })
    expect(wrapper.text()).toContain('In Entry')
  })

  describe('conditional sections by batch type', () => {
    it('hides allergies section for VITALS batch', () => {
      const wrapper = mountWithDraft({ batchType: 'VITALS' })
      expect(wrapper.text()).not.toContain('Allergies')
    })

    it('shows allergies section for ALLERGY_UPDATE batch', () => {
      const wrapper = mountWithDraft({ batchType: 'ALLERGY_UPDATE' })
      expect(wrapper.text()).toContain('Allergies')
      expect(wrapper.text()).toContain('No known allergies')
    })

    it('hides medications section for VITALS batch', () => {
      const wrapper = mountWithDraft({ batchType: 'VITALS' })
      expect(wrapper.text()).not.toContain('Medications')
    })

    it('shows medications section for MEDICATION_LIST batch', () => {
      const wrapper = mountWithDraft({ batchType: 'MEDICATION_LIST' })
      expect(wrapper.text()).toContain('Medications')
      expect(wrapper.text()).toContain('No active medications')
    })

    it('shows both allergies and medications for MIXED batch', () => {
      const wrapper = mountWithDraft({ batchType: 'MIXED' })
      expect(wrapper.text()).toContain('Allergies')
      expect(wrapper.text()).toContain('Medications')
    })

    it('hides encounter summary fields for VITALS batch', () => {
      const wrapper = mountWithDraft({ batchType: 'VITALS' })
      expect(wrapper.text()).not.toContain('Encounter Status')
      expect(wrapper.text()).not.toContain('Discharge Diagnosis')
    })

    it('shows encounter summary fields for ENCOUNTER_SUMMARY batch', () => {
      const wrapper = mountWithDraft({ batchType: 'ENCOUNTER_SUMMARY' })
      expect(wrapper.text()).toContain('Encounter Status')
      expect(wrapper.text()).toContain('Discharge Diagnosis')
    })
  })

  describe('draft loading', () => {
    it('populates patient fields from draft', async () => {
      const wrapper = mount(EntryForm, {
        props: { batch: makeBatch(), batchId: 'b1' },
      })

      const store = useBatchStore()
      store.currentDraft = emptyDraft('VITALS', {
        patient: {
          id: 'dp1',
          fullName: 'John Doe',
          dateOfBirth: '1990-05-15',
          sex: 'male',
          bloodType: 'O+',
          emergencyContact: '555-1234',
          allergies: null,
          noKnownAllergies: false,
          medications: null,
          noActiveMedications: false,
        },
        encounter: null,
        observations: [],
      })
      await wrapper.vm.$nextTick()

      const nameInput = wrapper.find<HTMLInputElement>('input[type="text"]')
      expect(nameInput.element.value).toBe('John Doe')
    })
  })

  describe('save on blur', () => {
    it('calls saveDraftPatient on patient field blur', async () => {
      const wrapper = mount(EntryForm, {
        props: { batch: makeBatch(), batchId: 'b1' },
      })

      const store = useBatchStore()
      store.saveDraftPatient = vi.fn().mockResolvedValue(undefined)

      const nameInput = wrapper.find('input[type="text"]')
      await nameInput.setValue('Jane Doe')
      await nameInput.trigger('blur')

      expect(store.saveDraftPatient).toHaveBeenCalledWith(
        'b1',
        expect.objectContaining({ fullName: 'Jane Doe' }),
      )
    })

    it('calls saveDraftEncounter on encounter field blur', async () => {
      const wrapper = mount(EntryForm, {
        props: { batch: makeBatch(), batchId: 'b1' },
      })

      const store = useBatchStore()
      store.saveDraftEncounter = vi.fn().mockResolvedValue(undefined)

      const roomInput = wrapper.findAll('input[type="text"]').find((i) => {
        const label = i.element.closest('div')?.querySelector('label')
        return label?.textContent?.includes('Room')
      })
      if (roomInput) {
        await roomInput.setValue('4B-01')
        await roomInput.trigger('blur')
        expect(store.saveDraftEncounter).toHaveBeenCalled()
      }
    })
  })

  describe('submit for verification', () => {
    it('calls submitForVerification on click', async () => {
      const wrapper = mount(EntryForm, {
        props: { batch: makeBatch(), batchId: 'b1' },
      })

      const store = useBatchStore()
      store.submitForVerification = vi.fn().mockResolvedValue(undefined)

      const submitBtn = wrapper.findAll('button').find((b) => b.text().includes('Submit for Verification'))
      await submitBtn!.trigger('click')
      await flushPromises()

      expect(store.submitForVerification).toHaveBeenCalledWith('b1')
    })

    it('displays error message on submit failure', async () => {
      const wrapper = mount(EntryForm, {
        props: { batch: makeBatch(), batchId: 'b1' },
      })

      const store = useBatchStore()
      store.submitForVerification = vi.fn().mockRejectedValue(new Error('BATCH_INCOMPLETE'))

      const submitBtn = wrapper.findAll('button').find((b) => b.text().includes('Submit for Verification'))
      await submitBtn!.trigger('click')
      await flushPromises()

      expect(wrapper.text()).toContain('BATCH_INCOMPLETE')
    })

    it('shows submitting state on button', async () => {
      let resolvePromise: () => void
      const wrapper = mount(EntryForm, {
        props: { batch: makeBatch(), batchId: 'b1' },
      })

      const store = useBatchStore()
      store.submitForVerification = vi.fn().mockReturnValue(
        new Promise<void>((resolve) => {
          resolvePromise = resolve
        }),
      )

      const submitBtn = wrapper.findAll('button').find((b) => b.text().includes('Submit for Verification'))
      await submitBtn!.trigger('click')
      await wrapper.vm.$nextTick()

      expect(wrapper.text()).toContain('Submitting...')

      resolvePromise!()
      await flushPromises()

      expect(wrapper.text()).toContain('Submit for Verification')
    })
  })

  describe('observations', () => {
    it('calls addObservation on add button click', async () => {
      const wrapper = mount(EntryForm, {
        props: { batch: makeBatch(), batchId: 'b1' },
      })

      const store = useBatchStore()
      store.addObservation = vi.fn().mockResolvedValue(undefined)

      const addBtn = wrapper.findAll('button').find((b) => b.text().includes('+ Add Observation'))
      await addBtn!.trigger('click')

      expect(store.addObservation).toHaveBeenCalledWith('b1', expect.objectContaining({
        observationCode: '',
        value: 0,
        unit: '',
      }))
    })
  })

  describe('blood type options', () => {
    it('renders all 8 blood type options plus empty', () => {
      const wrapper = mount(EntryForm, {
        props: { batch: makeBatch(), batchId: 'b1' },
      })
      const selects = wrapper.findAll('select')
      const bloodTypeSelect = selects.find((s) => {
        const opts = s.findAll('option')
        return opts.some((o) => o.text() === 'A+')
      })
      expect(bloodTypeSelect).toBeTruthy()
      const options = bloodTypeSelect!.findAll('option')
      expect(options.length).toBe(9) // "Unknown" + 8 blood types
    })
  })

  describe('department options', () => {
    it('renders department dropdown with clinical departments', () => {
      const wrapper = mount(EntryForm, {
        props: { batch: makeBatch(), batchId: 'b1' },
      })
      const selects = wrapper.findAll('select')
      const deptSelect = selects.find((s) => {
        const opts = s.findAll('option')
        return opts.some((o) => o.text() === 'ICU')
      })
      expect(deptSelect).toBeTruthy()
      const options = deptSelect!.findAll('option')
      expect(options.length).toBeGreaterThan(10)
    })
  })
})
