import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import { nextTick } from 'vue'
import { createPinia, setActivePinia } from 'pinia'
import CascadeFilter from '@/components/CascadeFilter.vue'

Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: (query: string) => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: () => {},
    removeListener: () => {},
    addEventListener: () => {},
    removeEventListener: () => {},
    dispatchEvent: () => false,
  }),
})

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

import { api } from '@/utils/request'

const mockCompanies = [
  { id: 1, name: 'acme', label: '阿克米公司', enabled: true },
  { id: 2, name: 'beta', label: '贝塔公司', enabled: true },
]

const mockPlatforms = [
  { id: 1, developer_id: 1 },
  { id: 2, developer_id: 2 },
]

const mockStores = [
  { id: 1, company_id: 1, platform_id: 1, name: 'store-a', label: 'A 店铺' },
  { id: 2, company_id: 1, platform_id: 2, name: 'store-b', label: 'B 店铺' },
  { id: 3, company_id: 2, platform_id: 1, name: 'store-c', label: 'C 店铺' },
]

function setupMocks() {
  vi.mocked(api.get).mockImplementation((url: string) => {
    if (url === '/api/v1/companies') return Promise.resolve(mockCompanies) as never
    if (url === '/api/v1/platforms') return Promise.resolve(mockPlatforms) as never
    if (url === '/api/v1/stores') return Promise.resolve(mockStores) as never
    return Promise.resolve([]) as never
  })
}

describe('CascadeFilter', () => {
  let wrapper: ReturnType<typeof mount>

  beforeEach(() => {
    vi.restoreAllMocks()
    document.body.innerHTML = ''
    setActivePinia(createPinia())
  })

  afterEach(() => {
    wrapper?.unmount()
    document.body.innerHTML = ''
  })

  async function mountFilter(props = {}) {
    wrapper = mount(CascadeFilter, {
      props: {
        modelValue: { company_id: undefined, platform_id: undefined, store_id: undefined },
        ...props,
      },
      attachTo: document.body,
    })
    await flushPromises()
    await nextTick()
    return wrapper
  }

  function queryBody(selector: string) {
    return document.body.querySelectorAll(selector)
  }

  it('渲染三个下拉框', async () => {
    setupMocks()
    await mountFilter()
    const selects = queryBody('.ant-select')
    expect(selects.length).toBe(3)
  })

  it('挂载时加载基础数据', async () => {
    setupMocks()
    await mountFilter()

    const calls = vi.mocked(api.get).mock.calls.map((c) => c[0])
    expect(calls).toContain('/api/v1/companies')
    expect(calls).toContain('/api/v1/platforms')
    expect(calls).toContain('/api/v1/stores')
  })

  it('选择公司后触发 update:modelValue', async () => {
    setupMocks()
    await mountFilter()

    // Simulate selecting company by triggering component method
    const vm = wrapper.vm as unknown as { handleCompanyChange: (val: unknown) => void }
    vm.handleCompanyChange(1)
    await nextTick()

    const emitted = wrapper.emitted('update:modelValue')
    expect(emitted).toBeTruthy()
    const lastEvent = emitted!.at(-1)!
    expect(lastEvent[0]).toEqual({
      company_id: 1,
      platform_id: undefined,
      store_id: undefined,
    })
  })

  it('选择平台后重置店铺', async () => {
    setupMocks()
    await mountFilter({
      modelValue: { company_id: 1, platform_id: undefined, store_id: 2 },
    })

    const vm = wrapper.vm as unknown as { handlePlatformChange: (val: unknown) => void }
    vm.handlePlatformChange(1)
    await nextTick()

    const emitted = wrapper.emitted('update:modelValue')
    expect(emitted).toBeTruthy()
    const lastEvent = emitted!.at(-1)!
    expect(lastEvent[0]).toEqual({
      company_id: 1,
      platform_id: 1,
      store_id: undefined,
    })
  })

  it('清空公司时重置平台和店铺', async () => {
    setupMocks()
    await mountFilter({
      modelValue: { company_id: 1, platform_id: 1, store_id: 2 },
    })

    const vm = wrapper.vm as unknown as { handleCompanyChange: (val: unknown) => void }
    vm.handleCompanyChange(undefined)
    await nextTick()

    const emitted = wrapper.emitted('update:modelValue')
    expect(emitted).toBeTruthy()
    const lastEvent = emitted!.at(-1)!
    expect(lastEvent[0]).toEqual({
      company_id: undefined,
      platform_id: undefined,
      store_id: undefined,
    })
  })

  it('API 失败时不崩溃', async () => {
    vi.mocked(api.get).mockRejectedValue(new Error('网络错误'))
    await mountFilter()

    const selects = queryBody('.ant-select')
    expect(selects.length).toBe(3)
  })
})
