import { renderHook, act, waitFor } from '@testing-library/react'
import { vi, describe, it, expect, beforeEach } from 'vitest'
import React from 'react'
import { createTestQueryClient } from '../../test/createTestQueryClient'
import { QueryClientProvider } from '@tanstack/react-query'

import * as api from '../../api/import'
import { useImport } from '../useImport'
import type { ImportSession, ImportPreview } from '../../api/import'

vi.mock('../../api/import', () => ({
  uploadCaddyfile: vi.fn(),
  getImportPreview: vi.fn(),
  commitImport: vi.fn(),
  getImportStatus: vi.fn(),
  cancelImport: vi.fn(),
}))

const wrapper = ({ children }: { children: React.ReactNode }) => {
  const qc = createTestQueryClient()
  return React.createElement(QueryClientProvider, { client: qc }, children)
}

describe('useImport (unit)', () => {
  beforeEach(() => vi.clearAllMocks())

  it('commit throws when there is no active session (guards)', async () => {
    vi.mocked(api.getImportStatus).mockResolvedValue({ has_pending: false })

    const { result } = renderHook(() => useImport(), { wrapper })

    await waitFor(() => expect(result.current.loading).toBe(false))

    await expect(result.current.commit({}, {})).rejects.toThrow(/No active session/)
  })

  it('does not surface preview error when there is no pending session', async () => {
    vi.mocked(api.getImportStatus).mockResolvedValue({ has_pending: false })
    vi.mocked(api.getImportPreview).mockRejectedValue(new Error('preview fail'))

    const { result } = renderHook(() => useImport(), { wrapper })

    await waitFor(() => expect(result.current.loading).toBe(false))
    // preview endpoint failed but there is no pending session => error should be null
    expect(result.current.error).toBeNull()
  })

  it('surfaces preview error when session is pending and commit not succeeded', async () => {
    vi.mocked(api.getImportStatus).mockResolvedValue({
      has_pending: true,
      session: { id: 's1', state: 'reviewing', created_at: '2026-01-31T00:00:00.000Z', updated_at: '2026-01-31T00:00:00.000Z' },
    })
    vi.mocked(api.getImportPreview).mockRejectedValue(new Error('preview fail'))

    const { result } = renderHook(() => useImport(), { wrapper })

    await waitFor(() => expect(result.current.loading).toBe(false))
    expect(result.current.error).toContain('preview fail')
  })

  it('enables preview query when session state is pending', async () => {
    const session: ImportSession = {
      id: 's-pending',
      state: 'pending',
      created_at: '2026-01-31T00:00:00.000Z',
      updated_at: '2026-01-31T00:00:00.000Z',
    }
    vi.mocked(api.getImportStatus).mockResolvedValue({ has_pending: true, session })
    const mockPreviewResponse: ImportPreview = {
      session,
      preview: { hosts: [], conflicts: [], errors: [] }
    }
    vi.mocked(api.getImportPreview).mockResolvedValue(mockPreviewResponse)

    const { result } = renderHook(() => useImport(), { wrapper })

    await waitFor(() => expect(result.current.loading).toBe(false))
    expect(api.getImportPreview).toHaveBeenCalled()
  })

  it('upload stores immediate uploadPreview and exposes preview', async () => {
    const mockPreview: ImportPreview = {
      session: { id: 's1', state: 'reviewing', created_at: '2026-01-31T00:00:00.000Z', updated_at: '2026-01-31T00:00:00.000Z' },
      preview: { hosts: [], conflicts: [], errors: [] },
    }
    vi.mocked(api.getImportStatus).mockResolvedValue({ has_pending: false })
    vi.mocked(api.uploadCaddyfile).mockResolvedValue(mockPreview)

    const { result } = renderHook(() => useImport(), { wrapper })

    await act(async () => {
      await result.current.upload('some content')
    })

    expect(api.uploadCaddyfile).toHaveBeenCalled()
    expect(result.current.preview).toEqual(mockPreview)
  })
})
