/**
 * StickyModeHeader (U2) 单元测试。
 *
 * 覆盖场景：
 * - @team 模式渲染 sticky 条（"专家团" badge + 任务目标 + 专家头像）
 * - @board 模式渲染 sticky 条（"私董会" badge + 主题 + 专家头像）
 * - 非 team/board 模式不渲染
 * - 头像 popover 内容（name / description / persona）
 * - Popover 打开（openChange true）→ 关闭（openChange false）→ 焦点回归触发头像
 * - 头像 > 5 时显示 +N 溢出标识，点击打开完整专家列表 popover
 *
 * Mount strategy: native Vue createApp + reactive props wrapper (no @vue/test-utils
 * dependency — happy-dom + vi.mock stubs keep the suite hermetic).
 *
 * 说明：viewport<768px 隐藏任务主题文本是 CSS media query 行为（声明式），
 * happy-dom 不计算 CSS，故不单独测试该场景 — 由 tokens.css + 组件 style 保证。
 */

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { computed, createApp, defineComponent, h, nextTick, reactive, ref, type Ref } from 'vue'

import type { IExpertTeamState, IExpertInfo } from '@/api/types'
import type { BoardState } from '@/stores/chatStream'

// ── 共享 mock 状态（vi.mock 工厂延迟执行，引用此处已初始化的 ref） ──
const teamState: Ref<IExpertTeamState | null> = ref(null)
const boardState: Ref<BoardState | null> = ref(null)

vi.mock('@/stores/team', () => ({
  useTeamStore: () =>
    reactive({
      teamState,
      activeExperts: computed(() =>
        teamState.value?.experts.filter((e) => e.status === 'active') || [],
      ),
      isTeamMode: computed(
        () =>
          teamState.value !== null && teamState.value.status !== 'dissolved',
      ),
    }),
}))

vi.mock('@/stores/chatStore', () => ({
  useChatStore: () => reactive({ boardState }),
}))

// ── Mock ant-design-vue Popover：受控渲染 + 点击触发 openChange ──
// 受控模式（open prop）：open=true 渲染 content；open=false 不渲染。
// 点击 trigger 时 emit openChange(!open)，让组件的 handleOpenChange 接管。
vi.mock('ant-design-vue', async () => {
  const { defineComponent, h } = await import('vue')
  const Popover = defineComponent({
    name: 'APopover',
    props: {
      trigger: { type: String, default: 'hover' },
      placement: { type: String, default: 'top' },
      open: { type: Boolean, default: undefined },
      overlayClassName: { type: String, default: '' },
    },
    emits: ['openChange'],
    setup(props, { slots, emit }) {
      return () => {
        const triggerEl = slots.default?.()
        const showContent = props.open === undefined ? true : props.open
        return h('div', { class: ['ant-popover-stub', props.overlayClassName] }, [
          h(
            'div',
            {
              class: 'ant-popover-stub__trigger',
              onClick: () => emit('openChange', !props.open),
            },
            triggerEl,
          ),
          showContent && slots.content
            ? h('div', { class: 'ant-popover-stub__content' }, slots.content())
            : null,
        ])
      }
    },
  })
  return { Popover }
})

const { default: StickyModeHeader } = await import(
  '@/components/chat/StickyModeHeader.vue'
)

// ── Fixtures ────────────────────────────────────────────────────────
function makeExpert(overrides: Partial<IExpertInfo> = {}): IExpertInfo {
  return {
    id: 'e1',
    name: '专家A',
    persona: '资深架构师',
    avatar: 'A',
    color: '#3b82f6',
    is_lead: false,
    bound_skills: ['react'],
    status: 'active',
    ...overrides,
  }
}

function makeTeamState(
  overrides: Partial<IExpertTeamState> = {},
): IExpertTeamState {
  return {
    team_id: 'team-1',
    status: 'executing',
    experts: [makeExpert()],
    plan_phases: [],
    lead_expert: '专家A',
    task_description: '实现用户登录功能',
    ...overrides,
  }
}

function makeBoardState(overrides: Partial<BoardState> = {}): BoardState {
  return {
    topic: '如何提升团队协作效率',
    experts: [
      {
        name: '主持人',
        avatar: 'T',
        color: '#a855f7',
        is_moderator: true,
        persona: '引导讨论',
      },
    ],
    max_rounds: 3,
    current_round: 1,
    status: 'discussing',
    ...overrides,
  }
}

// ── Mount helper ────────────────────────────────────────────────────
interface MountHandle {
  container: HTMLElement
  root: HTMLElement | null
  unmount: () => void
}

function mountStickyHeader(): MountHandle {
  const container = document.createElement('div')
  document.body.appendChild(container)
  const Wrapper = defineComponent({
    render() {
      return h(StickyModeHeader as never)
    },
  })
  const app = createApp(Wrapper)
  app.mount(container)
  const root = container.querySelector('.sticky-mode-header')
  return {
    container,
    root: root as HTMLElement | null,
    unmount() {
      app.unmount()
      container.remove()
    },
  }
}

// ── Tests ───────────────────────────────────────────────────────────
describe('StickyModeHeader (U2)', () => {
  beforeEach(() => {
    teamState.value = null
    boardState.value = null
  })

  afterEach(() => {
    teamState.value = null
    boardState.value = null
  })

  it('@team 模式渲染 sticky 条：专家团 badge + 任务目标 + 专家头像', async () => {
    teamState.value = makeTeamState({
      task_description: '实现用户登录功能',
      experts: [
        makeExpert({ id: 'e1', name: '专家A', avatar: 'A', is_lead: true }),
        makeExpert({ id: 'e2', name: '专家B', avatar: 'C' }),
      ],
    })
    const { container, unmount } = mountStickyHeader()
    await nextTick()

    const root = container.querySelector('.sticky-mode-header')
    expect(root).toBeTruthy()
    expect(root?.classList.contains('sticky-mode-header--team')).toBe(true)

    const badge = container.querySelector('.sticky-mode-header__badge')
    expect(badge?.textContent).toBe('专家团')

    const task = container.querySelector('.sticky-mode-header__task')
    expect(task?.textContent).toBe('实现用户登录功能')

    const avatars = container.querySelectorAll('.sticky-mode-header__avatar')
    expect(avatars.length).toBe(2)
    expect(avatars[0].textContent).toBe('A')

    unmount()
  })

  it('@team 模式无 task_description 时回退到首阶段 name', async () => {
    teamState.value = makeTeamState({
      task_description: undefined,
      plan_phases: [
        {
          id: 'p1',
          name: '需求分析',
          assigned_expert: '专家A',
          depends_on: [],
          status: 'in_progress',
        },
      ],
    })
    const { container, unmount } = mountStickyHeader()
    await nextTick()

    const task = container.querySelector('.sticky-mode-header__task')
    expect(task?.textContent).toBe('需求分析')

    unmount()
  })

  it('@board 模式渲染 sticky 条：私董会 badge + 主题 + 专家头像', async () => {
    boardState.value = makeBoardState({
      topic: '产品定价策略',
      experts: [
        {
          name: '主持人',
          avatar: 'T',
          color: '#a855f7',
          is_moderator: true,
          persona: '引导讨论',
        },
        {
          name: '专家1',
          avatar: 'I',
          color: '#3b82f6',
          is_moderator: false,
          persona: '市场分析',
        },
      ],
    })
    const { container, unmount } = mountStickyHeader()
    await nextTick()

    const root = container.querySelector('.sticky-mode-header')
    expect(root).toBeTruthy()
    expect(root?.classList.contains('sticky-mode-header--board')).toBe(true)

    const badge = container.querySelector('.sticky-mode-header__badge')
    expect(badge?.textContent).toBe('私董会')

    const task = container.querySelector('.sticky-mode-header__task')
    expect(task?.textContent).toBe('产品定价策略')

    const avatars = container.querySelectorAll('.sticky-mode-header__avatar')
    expect(avatars.length).toBe(2)

    unmount()
  })

  it('非 team/board 模式不渲染 sticky 条', async () => {
    const { container, unmount } = mountStickyHeader()
    await nextTick()

    expect(container.querySelector('.sticky-mode-header')).toBeNull()
    unmount()
  })

  it('@board 模式 status=dissolved 时不渲染', async () => {
    boardState.value = makeBoardState({ status: 'dissolved' })
    const { container, unmount } = mountStickyHeader()
    await nextTick()

    expect(container.querySelector('.sticky-mode-header')).toBeNull()
    unmount()
  })

  it('专家头像点击弹出 popover 显示 name/description/persona', async () => {
    teamState.value = makeTeamState({
      experts: [
        makeExpert({
          id: 'e1',
          name: '架构师',
          avatar: 'A',
          persona: '专注系统设计',
          bound_skills: ['react', 'vue'],
          is_lead: true,
        }),
      ],
    })
    const { container, unmount } = mountStickyHeader()
    await nextTick()

    const avatar = container.querySelector(
      '.sticky-mode-header__avatar',
    ) as HTMLElement
    expect(avatar).toBeTruthy()

    // 初始 popover 未打开（open=false → content 不渲染）
    expect(container.querySelector('.expert-detail')).toBeNull()

    // 点击头像 → openChange(true) → 组件设置 openKey → content 渲染
    avatar.click()
    await nextTick()

    const detail = container.querySelector('.expert-detail')
    expect(detail).toBeTruthy()
    expect(detail?.querySelector('.expert-detail__name')?.textContent).toBe(
      '架构师',
    )
    // description 来自 bound_skills（"技能: react, vue"）
    expect(detail?.querySelector('.expert-detail__desc')?.textContent).toBe(
      '技能: react, vue',
    )
    expect(detail?.querySelector('.expert-detail__persona')?.textContent).toBe(
      '专注系统设计',
    )

    unmount()
  })

  it('Popover 关闭后焦点回归触发头像', async () => {
    teamState.value = makeTeamState({
      experts: [makeExpert({ id: 'e1', name: '专家A' })],
    })
    const { container, unmount } = mountStickyHeader()
    await nextTick()

    const avatar = container.querySelector(
      '.sticky-mode-header__avatar',
    ) as HTMLButtonElement
    expect(avatar).toBeTruthy()

    // 打开 popover
    avatar.click()
    await nextTick()
    expect(container.querySelector('.expert-detail')).toBeTruthy()

    // 再次点击 → openChange(false) → 组件清除 openKey + 焦点回归
    avatar.click()
    await nextTick()

    expect(container.querySelector('.expert-detail')).toBeNull()
    // 焦点回归到触发头像
    expect(document.activeElement).toBe(avatar)

    unmount()
  })

  it('头像超过 5 个时显示 +N 溢出标识', async () => {
    const experts: IExpertInfo[] = Array.from({ length: 7 }, (_, i) =>
      makeExpert({
        id: `e${i + 1}`,
        name: `专家${i + 1}`,
        avatar: `${i + 1}`,
      }),
    )
    teamState.value = makeTeamState({ experts })

    const { container, unmount } = mountStickyHeader()
    await nextTick()

    // 5 个可见头像 + 1 个 +N 溢出标识
    const avatars = container.querySelectorAll('.sticky-mode-header__avatar')
    expect(avatars.length).toBe(6) // 5 visible + 1 overflow

    const overflow = container.querySelector(
      '.sticky-mode-header__avatar--overflow',
    )
    expect(overflow).toBeTruthy()
    expect(overflow?.textContent?.trim()).toBe('+2')

    unmount()
  })

  it('+N 点击打开完整专家列表 popover', async () => {
    const experts: IExpertInfo[] = Array.from({ length: 7 }, (_, i) =>
      makeExpert({
        id: `e${i + 1}`,
        name: `专家${i + 1}`,
        avatar: `${i + 1}`,
      }),
    )
    teamState.value = makeTeamState({ experts })

    const { container, unmount } = mountStickyHeader()
    await nextTick()

    const overflow = container.querySelector(
      '.sticky-mode-header__avatar--overflow',
    ) as HTMLButtonElement
    expect(overflow).toBeTruthy()

    // 初始无专家列表
    expect(container.querySelector('.expert-list')).toBeNull()

    // 点击 +N → 打开列表 popover
    overflow.click()
    await nextTick()

    const list = container.querySelector('.expert-list')
    expect(list).toBeTruthy()
    // 溢出专家 = 7 - 5 = 2
    const items = list?.querySelectorAll('.expert-list__item')
    expect(items?.length).toBe(2)

    unmount()
  })

  it('@team 模式 lead 头像标记 --lead 样式', async () => {
    teamState.value = makeTeamState({
      experts: [
        makeExpert({ id: 'e1', name: 'Lead', is_lead: true }),
        makeExpert({ id: 'e2', name: 'Member', is_lead: false }),
      ],
    })
    const { container, unmount } = mountStickyHeader()
    await nextTick()

    const avatars = container.querySelectorAll('.sticky-mode-header__avatar')
    expect(avatars[0].classList.contains('sticky-mode-header__avatar--lead'))
      .toBe(true)
    expect(avatars[1].classList.contains('sticky-mode-header__avatar--lead'))
      .toBe(false)

    unmount()
  })

  it('@board 模式主持人显示 description', async () => {
    boardState.value = makeBoardState({
      experts: [
        {
          name: '主持人',
          avatar: 'T',
          color: '#a855f7',
          is_moderator: true,
          persona: '引导者',
        },
      ],
    })
    const { container, unmount } = mountStickyHeader()
    await nextTick()

    const avatar = container.querySelector(
      '.sticky-mode-header__avatar',
    ) as HTMLButtonElement
    avatar.click()
    await nextTick()

    const desc = container.querySelector('.expert-detail__desc')
    expect(desc?.textContent).toBe('主持人')

    unmount()
  })

  it('sticky 定位使用 --z-sticky token', async () => {
    teamState.value = makeTeamState()
    const { container, unmount } = mountStickyHeader()
    await nextTick()

    const root = container.querySelector(
      '.sticky-mode-header',
    ) as HTMLElement
    expect(root).toBeTruthy()
    // position: sticky 由 CSS 设置，happy-dom 不计算样式
    // 断言 class 表明模式 token 应用
    expect(root.classList.contains('sticky-mode-header--team')).toBe(true)

    unmount()
  })
})
