/**
 * useAsset Composable测试
 *
 * 测试内容:
 * - 资产列表获取
 * - 资产详情获取
 * - 资产创建
 * - 资产更新
 * - 资产删除
 * - 错误处理
 */

import { describe, it, expect, vi, beforeEach } from 'vitest'
import { useAsset } from '@/composables/useAsset'
import * as assetApi from '@/api/assets'

// Mock API模块
vi.mock('@/api/assets', () => ({
  getAssetList: vi.fn(),
  getAssetById: vi.fn(),
  createAsset: vi.fn(),
  updateAsset: vi.fn(),
  deleteAsset: vi.fn(),
  importAssets: vi.fn()
}))

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

  describe('fetchAssets', () => {
    it('应该成功获取资产列表', async () => {
      const mockData = {
        items: [
          {
            id: 1,
            assetCode: 'ASSET-20250124-0001',
            assetName: '联想台式机',
            status: 'in_use'
          }
        ],
        total: 1,
        page: 1,
        pageSize: 20
      }

      vi.mocked(assetApi.getAssetList).mockResolvedValue(mockData)

      const { fetchAssets, assets, loading } = useAsset()
      await fetchAssets({ page: 1, page_size: 20 })

      expect(loading.value).toBe(false)
      expect(assets.value).toEqual(mockData.items)
      expect(assetApi.getAssetList).toHaveBeenCalledWith({ page: 1, page_size: 20 })
    })

    it('应该处理获取资产列表失败', async () => {
      vi.mocked(assetApi.getAssetList).mockRejectedValue(new Error('网络错误'))

      const { fetchAssets, loading } = useAsset()

      await expect(fetchAssets({ page: 1 })).rejects.toThrow('网络错误')
      expect(loading.value).toBe(false)
    })

    it('应该支持搜索参数', async () => {
      vi.mocked(assetApi.getAssetList).mockResolvedValue({ items: [], total: 0 })

      const { fetchAssets } = useAsset()
      await fetchAssets({
        page: 1,
        page_size: 20,
        keyword: '联想',
        status: 'in_use'
      })

      expect(assetApi.getAssetList).toHaveBeenCalledWith({
        page: 1,
        page_size: 20,
        keyword: '联想',
        status: 'in_use'
      })
    })
  })

  describe('fetchAssetById', () => {
    it('应该成功获取资产详情', async () => {
      const mockAsset = {
        id: 1,
        assetCode: 'ASSET-20250124-0001',
        assetName: '联想台式机',
        status: 'in_use'
      }

      vi.mocked(assetApi.getAssetById).mockResolvedValue(mockAsset)

      const { fetchAssetById, loading } = useAsset()
      const result = await fetchAssetById(1)

      expect(loading.value).toBe(false)
      expect(result).toEqual(mockAsset)
      expect(assetApi.getAssetById).toHaveBeenCalledWith(1)
    })

    it('应该处理资产不存在的情况', async () => {
      vi.mocked(assetApi.getAssetById).mockRejectedValue(new Error('资产不存在'))

      const { fetchAssetById } = useAsset()

      await expect(fetchAssetById(999)).rejects.toThrow('资产不存在')
    })
  })

  describe('createAsset', () => {
    it('应该成功创建资产', async () => {
      const newAsset = {
        assetName: '新资产',
        deviceTypeId: 1,
        organizationId: 1
      }

      const createdAsset = {
        id: 1,
        assetCode: 'ASSET-20250124-0001',
        ...newAsset
      }

      vi.mocked(assetApi.createAsset).mockResolvedValue(createdAsset)

      const { createAsset: create, loading } = useAsset()
      const result = await create(newAsset)

      expect(loading.value).toBe(false)
      expect(result).toEqual(createdAsset)
      expect(assetApi.createAsset).toHaveBeenCalledWith(newAsset)
    })

    it('应该处理创建失败', async () => {
      const newAsset = {
        assetName: '新资产',
        deviceTypeId: 1,
        organizationId: 1
      }

      vi.mocked(assetApi.createAsset).mockRejectedValue(new Error('创建失败'))

      const { createAsset: create } = useAsset()

      await expect(create(newAsset)).rejects.toThrow('创建失败')
    })

    it('应该验证必填字段', async () => {
      const invalidAsset = {
        assetName: '',  // 空名称
        deviceTypeId: 0,  // 无效ID
        organizationId: 1
      }

      const { createAsset: create } = useAsset()

      await expect(create(invalidAsset)).rejects.toThrow()
    })
  })

  describe('updateAsset', () => {
    it('应该成功更新资产', async () => {
      const updateData = {
        assetName: '更新后的名称',
        location: '新位置'
      }

      const updatedAsset = {
        id: 1,
        assetCode: 'ASSET-20250124-0001',
        ...updateData
      }

      vi.mocked(assetApi.updateAsset).mockResolvedValue(updatedAsset)

      const { updateAsset: update, loading } = useAsset()
      const result = await update(1, updateData)

      expect(loading.value).toBe(false)
      expect(result).toEqual(updatedAsset)
      expect(assetApi.updateAsset).toHaveBeenCalledWith(1, updateData)
    })

    it('应该处理更新不存在的资产', async () => {
      vi.mocked(assetApi.updateAsset).mockRejectedValue(new Error('资产不存在'))

      const { updateAsset: update } = useAsset()

      await expect(update(999, { assetName: '新名称' })).rejects.toThrow('资产不存在')
    })
  })

  describe('deleteAsset', () => {
    it('应该成功删除资产', async () => {
      vi.mocked(assetApi.deleteAsset).mockResolvedValue({})

      const { deleteAsset: deleteFn, loading } = useAsset()
      await deleteFn(1)

      expect(loading.value).toBe(false)
      expect(assetApi.deleteAsset).toHaveBeenCalledWith(1)
    })

    it('应该处理删除失败', async () => {
      vi.mocked(assetApi.deleteAsset).mockRejectedValue(new Error('删除失败'))

      const { deleteAsset: deleteFn } = useAsset()

      await expect(deleteFn(1)).rejects.toThrow('删除失败')
    })

    it('应该禁止删除使用中的资产', async () => {
      vi.mocked(assetApi.deleteAsset).mockRejectedValue(
        new Error('使用中的资产不能删除')
      )

      const { deleteAsset: deleteFn } = useAsset()

      await expect(deleteFn(1)).rejects.toThrow('使用中的资产不能删除')
    })
  })

  describe('importAssets', () => {
    it('应该成功导入资产', async () => {
      const mockFile = new File([''], 'test.xlsx', {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
      })

      const importResult = {
        total: 100,
        success: 98,
        failed: 2,
        errors: [
          { row: 5, message: '设备类型不存在' },
          { row: 12, message: '序列号重复' }
        ]
      }

      vi.mocked(assetApi.importAssets).mockResolvedValue(importResult)

      const { importAssets: importFn, loading } = useAsset()
      const result = await importFn(mockFile)

      expect(loading.value).toBe(false)
      expect(result).toEqual(importResult)
      expect(result.success).toBe(98)
      expect(result.failed).toBe(2)
    })

    it('应该处理导入失败', async () => {
      const mockFile = new File([''], 'test.xlsx')

      vi.mocked(assetApi.importAssets).mockRejectedValue(new Error('文件格式错误'))

      const { importAssets: importFn } = useAsset()

      await expect(importFn(mockFile)).rejects.toThrow('文件格式错误')
    })
  })

  describe('状态管理', () => {
    it('应该正确设置loading状态', async () => {
      vi.mocked(assetApi.getAssetList).mockImplementation(() =>
        new Promise(resolve => {
          setTimeout(() => {
            resolve({ items: [], total: 0 })
          }, 100)
        })
      )

      const { fetchAssets, loading } = useAsset()

      const promise = fetchAssets({ page: 1 })
      expect(loading.value).toBe(true)

      await promise
      expect(loading.value).toBe(false)
    })

    it('应该管理assets响应式数据', async () => {
      const mockData = {
        items: [
          { id: 1, assetName: '资产1' },
          { id: 2, assetName: '资产2' }
        ],
        total: 2
      }

      vi.mocked(assetApi.getAssetList).mockResolvedValue(mockData)

      const { fetchAssets, assets } = useAsset()
      await fetchAssets({ page: 1 })

      expect(assets.value.length).toBe(2)
      expect(assets.value[0].assetName).toBe('资产1')
    })
  })
})
