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 { message, Modal } from 'ant-design-vue'
import DataScopeModal from '@/components/DataScopeModal.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 mockScopes = {
  user_id: 1,
  role: 'accessor',
  scopes: [
    { scope_type: 'company', scope_id: 1, name: '阿克米公司' },
  ],
  resolved_store_ids: [5, 6],
}

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

const mockPlatforms = [
  { id: 1, name: 'shopify', label: 'Shopify', developer_id: 1 },
  { id: 2, name: 'amazon', label: 'Amazon', developer_id: 1 },
]

const mockStores = [
  { id: 5, company_id: 1, platform_id: 1, name: 'my-store', label: '我的店铺' },
  { id: 6, company_id: 1, platform_id: 2, name: 'store-2', label: '店铺二' },
  { id: 7, company_id: 2, platform_id: 1, name: 'beta-store', label: '贝塔店铺' },
]

function setupMocks(overrides: { scopes?: typeof mockScopes } = {}) {
  vi.mocked(api.get).mockImplementation((url: string) => {
    if (url.match(/\/users\/\d+\/data-scope/)) return Promise.resolve(overrides.scopes ?? mockScopes) as never
    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
  })
  vi.mocked(api.put).mockResolvedValue(undefined as never)
}

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

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

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

  async function mountModal(props = {}) {
    wrapper = mount(DataScopeModal, {
      props: {
        open: true,
        userId: 1,
        username: 'testuser',
        ...props,
      },
      attachTo: document.body,
    })
    await flushPromises()
    await nextTick()
    return wrapper
  }

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

  describe('树渲染', () => {
    it('公司模式下渲染 Company → Store 层级', async () => {
      setupMocks()
      await mountModal()

      const treeNodes = queryBody('.ant-tree-treenode')
      expect(treeNodes.length).toBeGreaterThanOrEqual(3)

      const titles = Array.from(queryBody('.ant-tree-title')).map((el) => el.textContent)
      expect(titles.some((t) => t?.includes('阿克米公司'))).toBe(true)
      expect(titles.some((t) => t?.includes('贝塔公司'))).toBe(true)
    })

    it('店铺节点标题包含平台名前缀', async () => {
      setupMocks()
      await mountModal()

      const titles = Array.from(queryBody('.ant-tree-title')).map((el) => el.textContent)
      expect(titles.some((t) => t?.includes('[Shopify]'))).toBe(true)
      expect(titles.some((t) => t?.includes('[Amazon]'))).toBe(true)
    })

    it('标题包含用户名', async () => {
      setupMocks()
      await mountModal()
      const title = document.body.querySelector('.ant-modal-title')
      expect(title?.textContent).toContain('testuser')
    })

    it('open=false 不渲染内容', async () => {
      setupMocks()
      await mountModal({ open: false })
      const modal = document.body.querySelector('.ant-modal')
      expect(modal).toBeNull()
    })
  })

  describe('平台模式', () => {
    it('切换到平台模式后渲染 Platform → Store 层级', async () => {
      setupMocks({
        scopes: { ...mockScopes, scopes: [] },
      })
      await mountModal()

      const segments = Array.from(queryBody('.ant-segmented-item'))
      const platformSeg = segments.find((el) => el.textContent?.includes('按平台授权'))
      expect(platformSeg).toBeTruthy()
      ;(platformSeg as HTMLElement).click()
      await flushPromises()
      await nextTick()

      const titles = Array.from(queryBody('.ant-tree-title')).map((el) => el.textContent)
      expect(titles.some((t) => t?.includes('Shopify'))).toBe(true)
    })
  })

  describe('模式切换确认', () => {
    it('有勾选项时切换模式弹出确认框', async () => {
      setupMocks()
      await mountModal()

      const confirmSpy = vi.spyOn(Modal, 'confirm')
      const segments = Array.from(queryBody('.ant-segmented-item'))
      const platformSeg = segments.find((el) => el.textContent?.includes('按平台授权'))
      ;(platformSeg as HTMLElement).click()
      await flushPromises()

      expect(confirmSpy).toHaveBeenCalled()
    })
  })

  describe('初始化', () => {
    it('已有 company scope 时打开弹窗后有勾选节点', async () => {
      setupMocks()
      await mountModal()

      const checkedBoxes = queryBody('.ant-tree-checkbox-checked')
      expect(checkedBoxes.length).toBeGreaterThanOrEqual(1)
    })

    it('已有 platform scope 时自动切换到平台模式', async () => {
      setupMocks({
        scopes: {
          ...mockScopes,
          scopes: [{ scope_type: 'platform', scope_id: 1, name: 'Shopify' }],
        },
      })
      await mountModal()

      const activeSegment = document.body.querySelector('.ant-segmented-item-selected')
      expect(activeSegment?.textContent).toContain('按平台授权')
    })
  })

  describe('搜索高亮', () => {
    it('搜索关键词后匹配节点文字被高亮', async () => {
      setupMocks({ scopes: { ...mockScopes, scopes: [] } })
      await mountModal()

      const input = document.body.querySelector('.ant-input-search input') as HTMLInputElement
      expect(input).toBeTruthy()

      if (input) {
        input.value = '阿克米'
        input.dispatchEvent(new Event('input', { bubbles: true }))
        await flushPromises()
        await nextTick()

        const highlighted = queryBody('.text-red-500')
        expect(highlighted.length).toBeGreaterThanOrEqual(1)
      }
    })
  })

  describe('保存逻辑', () => {
    it('全选公司节点保存为 company scope', async () => {
      setupMocks()
      await mountModal()

      const okBtn = Array.from(queryBody('.ant-btn-primary')).find(
        (btn) => btn.textContent?.includes('确') || btn.textContent?.includes('OK'),
      ) as HTMLElement
      if (okBtn) {
        okBtn.click()
        await flushPromises()
      }

      expect(vi.mocked(api.put)).toHaveBeenCalledWith(
        '/api/v1/users/1/data-scope',
        expect.objectContaining({
          scopes: expect.arrayContaining([
            expect.objectContaining({ scope_type: 'company', scope_id: 1 }),
          ]),
        }),
      )
    })

    it('保存成功显示 success message', async () => {
      setupMocks()
      const spy = vi.spyOn(message, 'success')
      await mountModal()

      const okBtn = Array.from(queryBody('.ant-btn-primary')).find(
        (btn) => btn.textContent?.includes('确') || btn.textContent?.includes('OK'),
      ) as HTMLElement
      if (okBtn) {
        okBtn.click()
        await flushPromises()
      }

      expect(spy).toHaveBeenCalledWith('数据范围保存成功')
    })

    it('API 失败显示 error message', async () => {
      setupMocks()
      vi.mocked(api.put).mockRejectedValueOnce(new Error('保存出错'))
      const spy = vi.spyOn(message, 'error')
      await mountModal()

      const okBtn = Array.from(queryBody('.ant-btn-primary')).find(
        (btn) => btn.textContent?.includes('确') || btn.textContent?.includes('OK'),
      ) as HTMLElement
      if (okBtn) {
        okBtn.click()
        await flushPromises()
      }

      expect(spy).toHaveBeenCalledWith('保存出错')
    })
  })

  describe('提示文案', () => {
    it('公司模式显示公司授权提示', async () => {
      setupMocks({ scopes: { ...mockScopes, scopes: [] } })
      await mountModal()

      const alert = document.body.querySelector('.ant-alert-message')
      expect(alert?.textContent).toContain('勾选公司节点')
    })
  })
})
