import React from 'react'

import {renderHook} from '@testing-library/react'
import {describe, expect, it, vi, beforeEach} from 'vitest'

import {useImagePicker} from './useImagePicker'

import type {
  OpenCameraParams,
  OpenGalleryParams,
} from '../../providers/ImagePickerProvider'

// Mock the ImagePickerProvider context
const mockOpenCamera = vi.fn()
const mockOpenGallery = vi.fn()

vi.mock('../../providers/ImagePickerProvider', () => ({
  useImagePickerContext: () => ({
    openCamera: mockOpenCamera,
    openGallery: mockOpenGallery,
  }),
  ImagePickerProvider: ({children}: {children: React.ReactNode}) => children,
}))

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

  describe('openCamera', () => {
    it('calls context openCamera with provided params', async () => {
      const mockFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'})
      mockOpenCamera.mockResolvedValue(mockFile)

      const {result} = renderHook(() => useImagePicker())

      const params: OpenCameraParams = {
        cameraFacing: 'front',
        quality: 'high',
        customQuality: {size: 2000, compression: 0.9},
      }

      const file = await result.current.openCamera(params)

      expect(mockOpenCamera).toHaveBeenCalledWith(params)
      expect(file).toBe(mockFile)
    })

    it('calls context openCamera with default params when none provided', async () => {
      const mockFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'})
      mockOpenCamera.mockResolvedValue(mockFile)

      const {result} = renderHook(() => useImagePicker())

      const file = await result.current.openCamera()

      expect(mockOpenCamera).toHaveBeenCalledWith({
        cameraFacing: undefined,
        quality: undefined,
        customQuality: undefined,
      })
      expect(file).toBe(mockFile)
    })

    it('supports partial params', async () => {
      const mockFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'})
      mockOpenCamera.mockResolvedValue(mockFile)

      const {result} = renderHook(() => useImagePicker())

      const file = await result.current.openCamera({quality: 'low'})

      expect(mockOpenCamera).toHaveBeenCalledWith({
        cameraFacing: undefined,
        quality: 'low',
        customQuality: undefined,
      })
      expect(file).toBe(mockFile)
    })
  })

  describe('openGallery', () => {
    it('calls context openGallery with provided params', async () => {
      const mockFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'})
      mockOpenGallery.mockResolvedValue(mockFile)

      const {result} = renderHook(() => useImagePicker())

      const params: OpenGalleryParams = {
        quality: 'medium',
        customQuality: {size: 1500, compression: 0.8},
      }

      const file = await result.current.openGallery(params)

      expect(mockOpenGallery).toHaveBeenCalledWith(params)
      expect(file).toBe(mockFile)
    })

    it('calls context openGallery with default params when none provided', async () => {
      const mockFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'})
      mockOpenGallery.mockResolvedValue(mockFile)

      const {result} = renderHook(() => useImagePicker())

      const file = await result.current.openGallery()

      expect(mockOpenGallery).toHaveBeenCalledWith({
        quality: undefined,
        customQuality: undefined,
      })
      expect(file).toBe(mockFile)
    })

    it('supports partial params', async () => {
      const mockFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'})
      mockOpenGallery.mockResolvedValue(mockFile)

      const {result} = renderHook(() => useImagePicker())

      const file = await result.current.openGallery({quality: 'original'})

      expect(mockOpenGallery).toHaveBeenCalledWith({
        quality: 'original',
        customQuality: undefined,
      })
      expect(file).toBe(mockFile)
    })
  })

  describe('Error handling', () => {
    it('propagates errors from openCamera', async () => {
      const error = new Error('Camera permission denied')
      mockOpenCamera.mockRejectedValue(error)

      const {result} = renderHook(() => useImagePicker())

      await expect(result.current.openCamera()).rejects.toThrow(
        'Camera permission denied'
      )
    })

    it('propagates errors from openGallery', async () => {
      const error = new Error('Gallery access denied')
      mockOpenGallery.mockRejectedValue(error)

      const {result} = renderHook(() => useImagePicker())

      await expect(result.current.openGallery()).rejects.toThrow(
        'Gallery access denied'
      )
    })
  })

  describe('Quality settings', () => {
    it('passes through all quality options for camera', async () => {
      const mockFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'})
      mockOpenCamera.mockResolvedValue(mockFile)

      const {result} = renderHook(() => useImagePicker())

      // Test each quality setting
      const qualities = ['low', 'medium', 'high', 'original'] as const

      for (const quality of qualities) {
        await result.current.openCamera({quality})
        expect(mockOpenCamera).toHaveBeenLastCalledWith({
          cameraFacing: undefined,
          quality,
          customQuality: undefined,
        })
      }
    })

    it('passes through all quality options for gallery', async () => {
      const mockFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'})
      mockOpenGallery.mockResolvedValue(mockFile)

      const {result} = renderHook(() => useImagePicker())

      // Test each quality setting
      const qualities = ['low', 'medium', 'high', 'original'] as const

      for (const quality of qualities) {
        await result.current.openGallery({quality})
        expect(mockOpenGallery).toHaveBeenLastCalledWith({
          quality,
          customQuality: undefined,
        })
      }
    })
  })
})
