import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { renderHook, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import type { ReactNode } from 'react'
import {
  useJobs,
  useJob,
  useCreateJob,
  useApproveEnglish,
  useRejectJob,
  useCompleteJob,
  useUpdateJobVtt,
} from '../useJob'
import type { VttUpdateRequest } from '../../types/api'
import { apiClient } from '../../lib/api'
import { mockApiResponses } from '../../test/utils'

// Mock the API client
vi.mock('../../lib/api', () => ({
  apiClient: {
    getJobs: vi.fn(),
    getJob: vi.fn(),
    createJob: vi.fn(),
    approveEnglish: vi.fn(),
    rejectJob: vi.fn(),
    completeJob: vi.fn(),
    updateJobVttContent: vi.fn(),
    getJobDownloads: vi.fn(),
    getJobVttContent: vi.fn(),
    validateJobAssets: vi.fn(),
  }
}))

const mockApiClient = vi.mocked(apiClient)

const createWrapper = () => {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        retry: false,
      },
      mutations: {
        retry: false,
      },
    },
  })

  return ({ children }: { children: ReactNode }) => (
    <QueryClientProvider client={queryClient}>
      {children}
    </QueryClientProvider>
  )
}

describe('Job Hooks', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  afterEach(() => {
    vi.clearAllMocks()
  })

  describe('useJobs', () => {
    it('fetches jobs successfully', async () => {
      mockApiClient.getJobs.mockResolvedValueOnce(mockApiResponses.jobs.jobList)

      const { result } = renderHook(() => useJobs(), {
        wrapper: createWrapper(),
      })

      await waitFor(() => expect(result.current.isSuccess).toBe(true))

      expect(result.current.data).toEqual(mockApiResponses.jobs.jobList)
      expect(mockApiClient.getJobs).toHaveBeenCalledWith(undefined)
    })

    it('passes filters to API call', async () => {
      const filters = { status: 'pending_qc', mine: true }
      mockApiClient.getJobs.mockResolvedValueOnce(mockApiResponses.jobs.jobList)

      const { result } = renderHook(() => useJobs(filters), {
        wrapper: createWrapper(),
      })

      await waitFor(() => expect(result.current.isSuccess).toBe(true))

      expect(mockApiClient.getJobs).toHaveBeenCalledWith(filters)
    })

    it('handles API error', async () => {
      const error = new Error('API Error')
      mockApiClient.getJobs.mockRejectedValueOnce(error)

      const { result } = renderHook(() => useJobs(), {
        wrapper: createWrapper(),
      })

      await waitFor(() => expect(result.current.isError).toBe(true))

      expect(result.current.error).toEqual(error)
    })
  })

  describe('useJob', () => {
    it('fetches single job successfully', async () => {
      const jobId = 'job-1'
      mockApiClient.getJob.mockResolvedValueOnce(mockApiResponses.jobs.jobDetail)

      const { result } = renderHook(() => useJob(jobId), {
        wrapper: createWrapper(),
      })

      await waitFor(() => expect(result.current.isSuccess).toBe(true))

      expect(result.current.data).toEqual(mockApiResponses.jobs.jobDetail)
      expect(mockApiClient.getJob).toHaveBeenCalledWith(jobId)
    })

    it('is disabled when jobId is empty', () => {
      mockApiClient.getJob.mockResolvedValueOnce(mockApiResponses.jobs.jobDetail)

      const { result } = renderHook(() => useJob(''), {
        wrapper: createWrapper(),
      })

      expect(result.current.isFetching).toBe(false)
      expect(mockApiClient.getJob).not.toHaveBeenCalled()
    })
  })

  describe('useCreateJob', () => {
    it('creates job successfully', async () => {
      const mockFile = new File([''], 'test.mp4', { type: 'video/mp4' })
      const jobRequest = {
        title: 'Test Job',
        language: 'en',
        requested_outputs: ['captions', 'audio_description']
      }

      mockApiClient.createJob.mockResolvedValueOnce(mockApiResponses.jobs.jobDetail)

      const { result } = renderHook(() => useCreateJob(), {
        wrapper: createWrapper(),
      })

      result.current.mutate({ data: jobRequest, file: mockFile })

      await waitFor(() => expect(result.current.isSuccess).toBe(true))

      expect(result.current.data).toEqual(mockApiResponses.jobs.jobDetail)
      expect(mockApiClient.createJob).toHaveBeenCalledWith(jobRequest, mockFile)
    })

    it('handles creation error', async () => {
      const error = new Error('Creation failed')
      const mockFile = new File([''], 'test.mp4', { type: 'video/mp4' })
      const jobRequest = {
        title: 'Test Job',
        language: 'en',
        requested_outputs: ['captions']
      }

      mockApiClient.createJob.mockRejectedValueOnce(error)

      const { result } = renderHook(() => useCreateJob(), {
        wrapper: createWrapper(),
      })

      result.current.mutate({ data: jobRequest, file: mockFile })

      await waitFor(() => expect(result.current.isError).toBe(true))

      expect(result.current.error).toEqual(error)
    })
  })

  describe('useApproveEnglish', () => {
    it('approves job successfully', async () => {
      const jobId = 'job-1'
      const notes = 'Approved with minor adjustments'

      mockApiClient.approveEnglish.mockResolvedValueOnce({
        ...mockApiResponses.jobs.jobDetail,
        status: 'approved_english'
      })

      const { result } = renderHook(() => useApproveEnglish(), {
        wrapper: createWrapper(),
      })

      result.current.mutate({ id: jobId, notes })

      await waitFor(() => expect(result.current.isSuccess).toBe(true))

      expect(mockApiClient.approveEnglish).toHaveBeenCalledWith(jobId, notes)
    })

    it('approves job without notes', async () => {
      const jobId = 'job-1'

      mockApiClient.approveEnglish.mockResolvedValueOnce({
        ...mockApiResponses.jobs.jobDetail,
        status: 'approved_english'
      })

      const { result } = renderHook(() => useApproveEnglish(), {
        wrapper: createWrapper(),
      })

      result.current.mutate({ id: jobId })

      await waitFor(() => expect(result.current.isSuccess).toBe(true))

      expect(mockApiClient.approveEnglish).toHaveBeenCalledWith(jobId, undefined)
    })
  })

  describe('useRejectJob', () => {
    it('rejects job successfully', async () => {
      const jobId = 'job-1'
      const notes = 'Quality issues found'

      mockApiClient.rejectJob.mockResolvedValueOnce({
        ...mockApiResponses.jobs.jobDetail,
        status: 'rejected'
      })

      const { result } = renderHook(() => useRejectJob(), {
        wrapper: createWrapper(),
      })

      result.current.mutate({ id: jobId, notes })

      await waitFor(() => expect(result.current.isSuccess).toBe(true))

      expect(mockApiClient.rejectJob).toHaveBeenCalledWith(jobId, notes)
    })
  })

  describe('useCompleteJob', () => {
    it('completes job successfully', async () => {
      const jobId = 'job-1'
      const notes = 'Final review complete'

      mockApiClient.completeJob.mockResolvedValueOnce({
        ...mockApiResponses.jobs.jobDetail,
        status: 'completed'
      })

      const { result } = renderHook(() => useCompleteJob(), {
        wrapper: createWrapper(),
      })

      result.current.mutate({ id: jobId, notes })

      await waitFor(() => expect(result.current.isSuccess).toBe(true))

      expect(mockApiClient.completeJob).toHaveBeenCalledWith(jobId, notes)
    })
  })

  describe('useUpdateJobVtt', () => {
    it('updates job VTT content successfully', async () => {
      const jobId = 'job-1'
      const vttData = {
        language: 'en',
        content_type: 'captions' as const,
        vtt_content: 'WEBVTT\n\n00:00:01.000 --> 00:00:03.000\nUpdated caption'
      }

      mockApiClient.updateJobVttContent.mockResolvedValueOnce(mockApiResponses.jobs.jobDetail)

      const { result } = renderHook(() => useUpdateJobVtt(), {
        wrapper: createWrapper(),
      })

      result.current.mutate({ id: jobId, data: vttData })

      await waitFor(() => expect(result.current.isSuccess).toBe(true))

      expect(mockApiClient.updateJobVttContent).toHaveBeenCalledWith(jobId, vttData)
    })
  })
})