import { describe, it, expect, vi, beforeEach } from 'vitest'
import {
  listCameras,
  getCamera,
  switchChannel,
  getCurrentChannel,
  ptzStart,
  ptzStop,
  adminListCameras,
  adminGetCamera,
  adminAddCamera,
  adminUpdateCamera,
  adminDeleteCamera,
  adminCheckCamera
} from '@/api/camera'
import * as request from '@/utils/request'
import { mockCameras, mockChannels, wrapResponse } from '../../fixtures'

vi.mock('@/utils/request', () => ({
  get: vi.fn(),
  post: vi.fn()
}))

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

  describe('Controller APIs', () => {
    describe('listCameras', () => {
      it('should call POST /camera/list', async () => {
        const mockResponse = wrapResponse(mockCameras)
        vi.mocked(request.post).mockResolvedValue(mockResponse)

        const result = await listCameras()

        expect(request.post).toHaveBeenCalledWith('/camera/list', {})
        expect(result.data).toHaveLength(mockCameras.length)
      })

      it('should call with machineId filter', async () => {
        vi.mocked(request.post).mockResolvedValue(wrapResponse([]))

        await listCameras('machine-001')

        expect(request.post).toHaveBeenCalledWith('/camera/list', { machineId: 'machine-001' })
      })
    })

    describe('getCamera', () => {
      it('should call GET /camera/:id', async () => {
        const camera = mockCameras[0]
        const mockResponse = wrapResponse(camera)
        vi.mocked(request.get).mockResolvedValue(mockResponse)

        const result = await getCamera(camera.cameraId)

        expect(request.get).toHaveBeenCalledWith(`/camera/${camera.cameraId}`)
        expect(result.data.cameraId).toBe(camera.cameraId)
      })
    })

    describe('switchChannel', () => {
      it('should call POST /camera/switch', async () => {
        const channel = mockChannels[0]
        const mockResponse = wrapResponse(channel)
        vi.mocked(request.post).mockResolvedValue(mockResponse)

        const result = await switchChannel({ machineId: 'machine-001', channelId: channel.channelId })

        expect(request.post).toHaveBeenCalledWith('/camera/switch', {
          machineId: 'machine-001',
          channelId: channel.channelId
        })
        expect(result.data.channelId).toBe(channel.channelId)
      })
    })

    describe('getCurrentChannel', () => {
      it('should call GET /camera/current', async () => {
        const channel = mockChannels[0]
        const mockResponse = wrapResponse(channel)
        vi.mocked(request.get).mockResolvedValue(mockResponse)

        const result = await getCurrentChannel('machine-001')

        expect(request.get).toHaveBeenCalledWith('/camera/current', { machineId: 'machine-001' })
        expect(result.data.channelId).toBe(channel.channelId)
      })
    })

    describe('ptzStart', () => {
      it('should call POST /camera/:id/ptz/start', async () => {
        const mockResponse = wrapResponse(null)
        vi.mocked(request.post).mockResolvedValue(mockResponse)

        await ptzStart('cam-001', 'up', 50)

        expect(request.post).toHaveBeenCalledWith('/camera/cam-001/ptz/start', undefined, {
          params: { action: 'up', speed: 50 }
        })
      })
    })

    describe('ptzStop', () => {
      it('should call POST /camera/:id/ptz/stop', async () => {
        const mockResponse = wrapResponse(null)
        vi.mocked(request.post).mockResolvedValue(mockResponse)

        await ptzStop('cam-001')

        expect(request.post).toHaveBeenCalledWith('/camera/cam-001/ptz/stop')
      })
    })
  })

  describe('Admin APIs', () => {
    describe('adminListCameras', () => {
      it('should call POST /admin/cameras/list', async () => {
        const mockResponse = wrapResponse({
          list: mockCameras,
          total: mockCameras.length,
          page: 1,
          size: 20,
          totalPages: 1,
          hasNext: false,
          hasPrevious: false
        })
        vi.mocked(request.post).mockResolvedValue(mockResponse)

        const result = await adminListCameras()

        expect(request.post).toHaveBeenCalledWith('/admin/cameras/list', {})
        expect(result.data.list).toHaveLength(mockCameras.length)
      })
    })

    describe('adminGetCamera', () => {
      it('should call GET /admin/cameras/detail', async () => {
        const camera = mockCameras[0]
        const mockResponse = wrapResponse(camera)
        vi.mocked(request.get).mockResolvedValue(mockResponse)

        const result = await adminGetCamera(camera.id)

        expect(request.get).toHaveBeenCalledWith('/admin/cameras/detail', { id: camera.id })
        expect(result.data.id).toBe(camera.id)
      })
    })

    describe('adminAddCamera', () => {
      it('should call POST /admin/cameras/add', async () => {
        const newCamera = { ...mockCameras[0], id: 100, cameraId: 'cam-new' }
        const mockResponse = wrapResponse(newCamera)
        vi.mocked(request.post).mockResolvedValue(mockResponse)

        const addData = {
          cameraId: 'cam-new',
          name: '新摄像头',
          ip: '192.168.1.100',
          port: 80
        }
        const result = await adminAddCamera(addData)

        expect(request.post).toHaveBeenCalledWith('/admin/cameras/add', addData)
        expect(result.data.cameraId).toBe('cam-new')
      })
    })

    describe('adminUpdateCamera', () => {
      it('should call POST /admin/cameras/update', async () => {
        const updatedCamera = { ...mockCameras[0], name: '更新后名称' }
        const mockResponse = wrapResponse(updatedCamera)
        vi.mocked(request.post).mockResolvedValue(mockResponse)

        const updateData = { id: mockCameras[0].id, name: '更新后名称' }
        const result = await adminUpdateCamera(updateData)

        expect(request.post).toHaveBeenCalledWith('/admin/cameras/update', updateData)
        expect(result.data.name).toBe('更新后名称')
      })
    })

    describe('adminDeleteCamera', () => {
      it('should call POST /admin/cameras/delete', async () => {
        const mockResponse = wrapResponse(null)
        vi.mocked(request.post).mockResolvedValue(mockResponse)

        await adminDeleteCamera(1)

        expect(request.post).toHaveBeenCalledWith('/admin/cameras/delete', undefined, {
          params: { id: 1 }
        })
      })
    })

    describe('adminCheckCamera', () => {
      it('should call POST /admin/cameras/check', async () => {
        const mockResponse = wrapResponse(true)
        vi.mocked(request.post).mockResolvedValue(mockResponse)

        const result = await adminCheckCamera(1)

        expect(request.post).toHaveBeenCalledWith('/admin/cameras/check', undefined, {
          params: { id: 1 }
        })
        expect(result.data).toBe(true)
      })
    })
  })
})
