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 AdminApiKeyPage from '../index.vue'
import { useAdminApiKeyStore } from '@/stores/admin-api-key'
import type { ApiKeyRecord } from '@/types/api'

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(),
    patch: vi.fn(),
    delete: vi.fn(),
  },
}))

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

const mockRecord = (overrides: Partial<ApiKeyRecord> = {}): ApiKeyRecord => ({
  id: 1,
  user_id: 10,
  name: '测试Key',
  key_prefix: 'abc12345',
  last_used_at: null,
  expires_at: null,
  enabled: true,
  created_at: '2026-04-01T10:00:00',
  user: { id: 10, username: 'alice', api_key_enabled: true },
  ...overrides,
})

function setupApi(keys: ApiKeyRecord[] = []) {
  vi.mocked(api.get).mockResolvedValue({
    items: keys,
    total: keys.length,
    page: 1,
    per_page: 15,
  } as never)
  vi.mocked(api.patch).mockResolvedValue(undefined as never)
  vi.mocked(api.delete).mockResolvedValue(undefined as never)
}

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

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

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

  async function mountPage() {
    setupApi([mockRecord()])
    wrapper = mount(AdminApiKeyPage, { attachTo: document.body })
    await flushPromises()
    await nextTick()
    return wrapper
  }

  it('挂载时调用 fetchAllKeys', async () => {
    setupApi([])
    wrapper = mount(AdminApiKeyPage, { attachTo: document.body })
    await flushPromises()

    expect(vi.mocked(api.get)).toHaveBeenCalledWith(
      '/api/v1/admin/api-keys',
      expect.objectContaining({ page: 1 }),
    )
  })

  it('搜索按钮触发 fetchAllKeys 且 pagination.page 重置为 1', async () => {
    await mountPage()
    const store = useAdminApiKeyStore()
    store.pagination.page = 3

    vi.mocked(api.get).mockClear()
    setupApi([])

    const btn = Array.from(document.body.querySelectorAll('.ant-btn')).find((b) =>
      b.textContent?.includes('搜索'),
    ) as HTMLElement
    btn?.click()
    await flushPromises()

    expect(store.pagination.page).toBe(1)
    expect(vi.mocked(api.get)).toHaveBeenCalled()
  })

  it('重置按钮调用 resetFilters 并 fetchAllKeys', async () => {
    await mountPage()
    const store = useAdminApiKeyStore()
    store.filters.username = 'testuser'
    store.filters.email = 'test@example.com'

    vi.mocked(api.get).mockClear()
    setupApi([])

    const btn = Array.from(document.body.querySelectorAll('.ant-btn')).find((b) =>
      b.textContent?.includes('重置'),
    ) as HTMLElement
    btn?.click()
    await flushPromises()

    expect(store.filters.username).toBeUndefined()
    expect(store.filters.email).toBeUndefined()
    expect(vi.mocked(api.get)).toHaveBeenCalled()
  })

  it('api_key_enabled = false → 渲染红色"已停用"标签', async () => {
    setupApi([mockRecord({ user: { id: 10, username: 'bob', api_key_enabled: false } })])
    wrapper = mount(AdminApiKeyPage, { attachTo: document.body })
    await flushPromises()
    await nextTick()

    expect(document.body.innerHTML).toContain('已停用')
  })

  it('api_key_enabled = undefined → 不渲染"已停用"标签', async () => {
    setupApi([mockRecord({ user: { id: 10, username: 'carol' } })])
    wrapper = mount(AdminApiKeyPage, { attachTo: document.body })
    await flushPromises()
    await nextTick()

    expect(document.body.innerHTML).not.toContain('已停用')
  })

  it('Switch 切换调用 store.toggleKey(id, enabled)', async () => {
    await mountPage()
    const store = useAdminApiKeyStore()
    const spy = vi.spyOn(store, 'toggleKey').mockResolvedValue()

    const sw = document.body.querySelector('.ant-switch') as HTMLElement
    sw?.click()
    await flushPromises()

    expect(spy).toHaveBeenCalledWith(1, expect.any(Boolean))
  })

  it('空列表时表格正常渲染（无崩溃）', async () => {
    setupApi([])
    wrapper = mount(AdminApiKeyPage, { attachTo: document.body })
    await flushPromises()
    await nextTick()

    expect(document.body.querySelector('.ant-table')).toBeTruthy()
  })
})
