import { describe, it, expect, vi, beforeEach } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import { setActivePinia, createPinia } from 'pinia'
import ApprovalForm from '@/components/ApprovalForm.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(),
  }),
}))

const mountOptions = {
  global: {
    stubs: {
      Teleport: { template: '<div><slot /></div>' },
    },
  },
}

function makeBatch(overrides: Partial<BatchDetailResponse> = {}): BatchDetailResponse {
  const batchType = overrides.batchType ?? 'VITALS'
  return {
    id: 'b1',
    status: 'AWAITING_CLINICAL_APPROVAL',
    batchType,
    track: 'TRACK_A',
    fieldRequirements: fieldRequirementsForBatchType(batchType),
    patientId: 'p1',
    documentRef: 'docs/scan.pdf',
    documentUrl: null,
    enableRetroactiveAlerts: false,
    enteredByUserId: 'u1',
    verifiedByUserId: 'v1-aaaaaaa',
    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 mountForm(opts: {
  batch?: BatchDetailResponse
  draft?: ReturnType<typeof emptyDraft>
} = {}) {
  const batch = opts.batch ?? makeBatch()
  const draft =
    opts.draft ??
    emptyDraft(batch.batchType, {
      patient: {
        id: 'dp1',
        fullName: 'Jane Doe',
        dateOfBirth: '1990-05-15',
        sex: 'female',
        bloodType: 'A+',
        emergencyContact: '555-1234',
        allergies: ['Penicillin'],
        noKnownAllergies: false,
        medications: ['Metoprolol 50mg'],
        noActiveMedications: false,
      },
      encounter: {
        id: 'de1',
        batchId: 'b1',
        admissionDate: '2026-06-20T08:00:00',
        department: 'ICU',
        roomBed: '3A-12',
        admissionReason: 'Chest pain',
        dischargeDiagnosis: null,
        status: null,
      },
      observations: [
        {
          id: 'obs-1',
          batchId: 'b1',
          observationCode: 'TEMP_C',
          value: 38.4,
          unit: 'C',
          recordedAt: '2026-06-27T10:00:00Z',
          note: null,
        },
      ],
    })

  return mount(ApprovalForm, {
    props: { batch, batchId: 'b1', draft },
    ...mountOptions,
  })
}

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

describe('ApprovalForm', () => {
  it('uses clinical framing distinct from verification', () => {
    const wrapper = mountForm()
    expect(wrapper.find('[data-testid="approval-form"]').classes()).toContain('approval-frame')
    expect(wrapper.text()).toContain('Clinical Approval')
    expect(wrapper.text()).toContain('Clinical sign-off before promotion')
    expect(wrapper.text()).toContain('Verified draft')
  })

  it('highlights high-stakes fields from draft data', () => {
    const wrapper = mountForm()
    const summary = wrapper.find('[data-testid="high-stakes-summary"]')
    expect(summary.exists()).toBe(true)
    expect(summary.text()).toContain('Blood type')
    expect(summary.text()).toContain('A+')
    expect(summary.text()).toContain('Allergies')
    expect(summary.text()).toContain('Penicillin')
    expect(summary.text()).toContain('Medications')
    expect(summary.text()).toContain('Metoprolol')
    expect(summary.text()).toContain('TEMP C')
    expect(summary.text()).toContain('38.4')
  })

  it('uses design-doc retroactive alerts copy', () => {
    const wrapper = mountForm()
    expect(wrapper.text()).toContain('Run alert evaluation after promotion')
    expect(wrapper.text()).toContain(
      'May generate alerts for clinical criteria represented in historical records'
    )
  })

  it('shows Approve & Promote confirm dialog with live promotion copy', async () => {
    const wrapper = mountForm()
    await wrapper.find('[data-testid="approve-promote"]').trigger('click')
    await wrapper.vm.$nextTick()

    expect(wrapper.text()).toContain('Approve & Promote')
    expect(wrapper.text()).toContain(
      'Approval will promote the verified records into live clinical tables.'
    )
  })

  it('calls approveBatch with retroactive alerts flag', async () => {
    const wrapper = mountForm()
    const store = useBatchStore()
    store.approveBatch = vi.fn().mockResolvedValue({
      status: 200,
      data: { mrn: 'MRN-1', encounterId: 'enc-aaaaaaaa', observationIds: ['o1', 'o2'] },
    })

    await wrapper.find('[data-testid="retroactive-alerts"]').setValue(true)
    await wrapper.find('[data-testid="approve-promote"]').trigger('click')
    await wrapper.vm.$nextTick()

    const confirm = wrapper
      .findAll('[data-testid="confirm-dialog"] button')
      .find((b) => b.text() === 'Approve & Promote')
    await confirm!.trigger('click')
    await flushPromises()

    expect(store.approveBatch).toHaveBeenCalledWith('b1', true)
    expect(wrapper.find('[data-testid="promotion-result"]').exists()).toBe(true)
    expect(wrapper.text()).toContain('Promoted to live clinical tables')
    expect(wrapper.text()).toContain('MRN-1')
    expect(wrapper.text()).toContain('Promotion outcome')
  })

  it('opens Reject Batch dialog and posts reason', async () => {
    const wrapper = mountForm()
    const store = useBatchStore()
    store.rejectBatch = vi.fn().mockResolvedValue(undefined)

    await wrapper.find('[data-testid="reject-batch"]').trigger('click')
    await wrapper.vm.$nextTick()

    expect(wrapper.text()).toContain('Reject Batch')
    await wrapper.find('textarea').setValue('Incorrect patient')
    await wrapper.vm.$nextTick()

    const confirm = wrapper
      .findAll('[data-testid="confirm-dialog"] button')
      .find((b) => b.text() === 'Reject Batch')
    await confirm!.trigger('click')
    await flushPromises()

    expect(store.rejectBatch).toHaveBeenCalledWith('b1', 'Incorrect patient')
    expect(wrapper.emitted('rejected')).toHaveLength(1)
  })

  it('shows deferred promotion state', async () => {
    const wrapper = mountForm()
    const store = useBatchStore()
    store.approveBatch = vi.fn().mockResolvedValue({ status: 202 })

    await wrapper.find('[data-testid="approve-promote"]').trigger('click')
    await wrapper.vm.$nextTick()
    const confirm = wrapper
      .findAll('[data-testid="confirm-dialog"] button')
      .find((b) => b.text() === 'Approve & Promote')
    await confirm!.trigger('click')
    await flushPromises()

    expect(wrapper.find('[data-testid="promotion-deferred"]').exists()).toBe(true)
  })
})
