import { describe, it, expect, vi, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useDashboardStore } from '../dashboard'

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

const mockOverview = {
  today: { success: 10, failed: 2 },
  this_week: { success: 50, failed: 5 },
  this_month: { success: 200, failed: 20 },
  by_type: [
    { data_type: 'order', success: 80, failed: 10 },
    { data_type: 'product', success: 60, failed: 5 },
    { data_type: 'refund', success: 40, failed: 3 },
    { data_type: 'inventory', success: 20, failed: 2 },
  ],
}

const mockTrendData = [
  { date: '2026-03-18', success: 30, failed: 2 },
  { date: '2026-03-19', success: 25, failed: 3 },
  { date: '2026-03-20', success: 40, failed: 1 },
]

const mockBreakdownData = [
  { id: 1, name: 'Acme Corp', success: 100, failed: 10 },
  { id: 2, name: 'Beta Inc', success: 80, failed: 5 },
]

describe('useDashboardStore', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
    vi.restoreAllMocks()
  })

  describe('initial state', () => {
    it('S1: starts with correct initial state', () => {
      const store = useDashboardStore()
      expect(store.overview).toBeNull()
      expect(store.overviewLoading).toBe(false)
      expect(store.trendData).toEqual([])
      expect(store.trendGroupBy).toBe('day')
      expect(store.breakdownData).toEqual([])
      expect(store.breakdownDimension).toBe('company')
    })
  })

  describe('fetchOverview', () => {
    it('S2: fetches overview data successfully', async () => {
      const { api } = await import('@/utils/request')
      vi.mocked(api.get).mockResolvedValueOnce(mockOverview)

      const store = useDashboardStore()
      await store.fetchOverview()

      expect(api.get).toHaveBeenCalledWith('/api/v1/dashboard/overview')
      expect(store.overview).toEqual(mockOverview)
      expect(store.overviewLoading).toBe(false)
      expect(store.overviewError).toBe('')
    })

    it('S3: handles overview fetch error', async () => {
      const { api } = await import('@/utils/request')
      vi.mocked(api.get).mockRejectedValueOnce(new Error('网络错误'))

      const store = useDashboardStore()
      await store.fetchOverview()

      expect(store.overview).toBeNull()
      expect(store.overviewError).toBe('网络错误')
      expect(store.overviewLoading).toBe(false)
    })
  })

  describe('fetchTrend', () => {
    it('S4: fetches trend data with default params', async () => {
      const { api } = await import('@/utils/request')
      vi.mocked(api.get).mockResolvedValueOnce(mockTrendData)

      const store = useDashboardStore()
      await store.fetchTrend()

      expect(api.get).toHaveBeenCalledWith('/api/v1/dashboard/trend', expect.objectContaining({
        group_by: 'day',
      }))
      expect(store.trendData).toEqual(mockTrendData)
    })

    it('S5: passes filter params to trend API', async () => {
      const { api } = await import('@/utils/request')
      vi.mocked(api.get).mockResolvedValueOnce(mockTrendData)

      const store = useDashboardStore()
      store.trendGroupBy = 'week'
      store.trendDataType = 'order'
      store.trendFrom = '2026-03-01'
      store.trendTo = '2026-03-20'
      await store.fetchTrend()

      expect(api.get).toHaveBeenCalledWith('/api/v1/dashboard/trend', expect.objectContaining({
        group_by: 'week',
        data_type: 'order',
        from: '2026-03-01',
        to: '2026-03-20',
      }))
    })

    it('S6: handles trend fetch error', async () => {
      const { api } = await import('@/utils/request')
      vi.mocked(api.get).mockRejectedValueOnce(new Error('趋势接口超时'))

      const store = useDashboardStore()
      await store.fetchTrend()

      expect(store.trendData).toEqual([])
      expect(store.trendError).toBe('趋势接口超时')
    })
  })

  describe('fetchBreakdown', () => {
    it('S7: fetches breakdown data with default params', async () => {
      const { api } = await import('@/utils/request')
      vi.mocked(api.get).mockResolvedValueOnce(mockBreakdownData)

      const store = useDashboardStore()
      await store.fetchBreakdown()

      expect(api.get).toHaveBeenCalledWith('/api/v1/dashboard/breakdown', expect.objectContaining({
        dimension: 'company',
      }))
      expect(store.breakdownData).toEqual(mockBreakdownData)
    })

    it('S8: passes filter params to breakdown API', async () => {
      const { api } = await import('@/utils/request')
      vi.mocked(api.get).mockResolvedValueOnce(mockBreakdownData)

      const store = useDashboardStore()
      store.breakdownDimension = 'store'
      store.breakdownDataType = 'refund'
      store.breakdownFrom = '2026-03-01'
      store.breakdownTo = '2026-03-20'
      await store.fetchBreakdown()

      expect(api.get).toHaveBeenCalledWith('/api/v1/dashboard/breakdown', expect.objectContaining({
        dimension: 'store',
        data_type: 'refund',
        from: '2026-03-01',
        to: '2026-03-20',
      }))
    })

    it('S9: handles breakdown fetch error', async () => {
      const { api } = await import('@/utils/request')
      vi.mocked(api.get).mockRejectedValueOnce(new Error('分维度接口失败'))

      const store = useDashboardStore()
      await store.fetchBreakdown()

      expect(store.breakdownData).toEqual([])
      expect(store.breakdownError).toBe('分维度接口失败')
    })
  })

  describe('fetchAll', () => {
    it('S10: calls all three fetch functions in parallel', async () => {
      const { api } = await import('@/utils/request')
      vi.mocked(api.get).mockImplementation((url: string) => {
        if (url.includes('overview')) return Promise.resolve(mockOverview) as never
        if (url.includes('trend')) return Promise.resolve(mockTrendData) as never
        if (url.includes('breakdown')) return Promise.resolve(mockBreakdownData) as never
        return Promise.resolve(null) as never
      })

      const store = useDashboardStore()
      await store.fetchAll()

      expect(store.overview).toEqual(mockOverview)
      expect(store.trendData).toEqual(mockTrendData)
      expect(store.breakdownData).toEqual(mockBreakdownData)
    })

    it('S11: one API failure does not block others', async () => {
      const { api } = await import('@/utils/request')
      vi.mocked(api.get).mockImplementation((url: string) => {
        if (url.includes('overview')) return Promise.reject(new Error('概览失败')) as never
        if (url.includes('trend')) return Promise.resolve(mockTrendData) as never
        if (url.includes('breakdown')) return Promise.resolve(mockBreakdownData) as never
        return Promise.resolve(null) as never
      })

      const store = useDashboardStore()
      await store.fetchAll()

      expect(store.overview).toBeNull()
      expect(store.overviewError).toBe('概览失败')
      expect(store.trendData).toEqual(mockTrendData)
      expect(store.breakdownData).toEqual(mockBreakdownData)
    })
  })
})
