import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createPinia, setActivePinia } from 'pinia'
import { nextTick } from 'vue'

const mocks = vi.hoisted(() => ({
  chatStream: vi.fn(),
  list: vi.fn(),
  getMessages: vi.fn(),
  deleteConversation: vi.fn(),
  settingsGet: vi.fn(),
  upload: vi.fn(),
  systemStatusGet: vi.fn(),
}))

vi.mock('@/api/conversation', () => ({
  conversationApi: {
    chatStream: mocks.chatStream,
    list: mocks.list,
    getMessages: mocks.getMessages,
    delete: mocks.deleteConversation,
  },
}))

vi.mock('@/api/settings', () => ({
  settingsApi: {
    get: mocks.settingsGet,
  },
}))

vi.mock('@/api/system', () => ({
  systemApi: {
    getStatus: mocks.systemStatusGet,
  },
}))

vi.mock('@/api/document', () => ({
  documentApi: {
    upload: mocks.upload,
  },
}))

vi.mock('@/stores/auth', () => ({
  useAuthStore: () => ({
    ensureAuthReady: vi.fn().mockResolvedValue(undefined),
    isAuthenticated: true,
    user: { id: 'user-1', email: 'test@example.com' },
  }),
}))

import { useChatView } from './useChatView'

describe('useChatView orchestration state', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
    vi.useFakeTimers()
    vi.clearAllMocks()
    mocks.list.mockResolvedValue({ data: [] })
    mocks.getMessages.mockResolvedValue({ data: [] })
    mocks.deleteConversation.mockResolvedValue(undefined)
    mocks.settingsGet.mockResolvedValue({
      data: {
        llm_config: {
          chat: [
            {
              name: 'Jarvis Chat',
              provider: 'openai',
              model: 'gpt-test',
              base_url: '',
              api_key: '',
              enabled: true,
            },
          ],
          vlm: [],
        },
      },
    })
    mocks.upload.mockResolvedValue({ data: { id: 'file-1' } })
    mocks.systemStatusGet.mockResolvedValue({
      data: {
        cpu_percent: 21,
        memory_percent: 48,
        disk_percent: 63,
        timestamp: '2026-03-22T02:40:00Z',
      },
    })
  })

  it('derives telemetry state from real system status and session events without persisting it to message history', async () => {
    mocks.chatStream.mockImplementation(async (_message, _conversationId, _fileIds, _modelName, handlers) => {
      handlers.onMetadata?.({ conversation_id: 'conv-1', message_id: 'msg-1' })
      handlers.onProgress?.({
        stage: 'tool',
        label: 'Jarvis 正在调用工具',
        agent: 'executor',
        tool_name: 'search_knowledge',
        step: '调用工具 search_knowledge',
        steps: ['理解问题', '检索知识'],
      })
      handlers.onChunk?.({ content: '最终回复' })
    })

    const view = useChatView()
    await nextTick()
    await Promise.resolve()

    expect(mocks.systemStatusGet).toHaveBeenCalledTimes(1)
    expect(view.systemTelemetry.value.cpu.current).toBe(21)
    expect(view.systemTelemetry.value.memory.current).toBe(48)
    expect(view.systemTelemetry.value.disk.current).toBe(63)
    expect(view.systemTelemetry.value.cpu.series.at(-1)).toBe(21)

    view.inputMessage.value = '测试问题'
    const promise = view.sendMessage()
    await Promise.resolve()

    expect(view.sessionTelemetry.value.eventsCount).toBe(2)
    expect(view.sessionTelemetry.value.toolCount).toBe(1)
    expect(view.sessionTelemetry.value.agentCount).toBe(1)
    expect(view.sessionTelemetry.value.activitySeries.some((point) => point > 0)).toBe(true)
    expect(view.store.messages).toHaveLength(1)

    await promise

    expect(view.store.messages).toHaveLength(2)
    expect(view.store.messages.every((message) => !('activitySeries' in message))).toBe(true)
  })

  it('keeps the orchestration panel persistent and confines thinking state to the side panel', async () => {
    mocks.chatStream.mockImplementation(async (_message, _conversationId, _fileIds, _modelName, handlers) => {
      handlers.onMetadata?.({ conversation_id: 'conv-1', message_id: 'msg-1' })
      handlers.onProgress?.({
        stage: 'planning',
        label: 'Jarvis 正在拆解步骤',
        agent: 'planner',
        tool_name: null,
        step: '正在分配任务',
        steps: ['理解问题', '分配 planner'],
      })
      handlers.onChunk?.({ content: '最终回复' })
    })

    const view = useChatView()
    view.inputMessage.value = '测试问题'

    const promise = view.sendMessage()
    await Promise.resolve()

    expect(view.store.messages).toHaveLength(1)
    expect(view.store.messages[0].role).toBe('user')
    expect(view.isTyping.value).toBe(true)
    expect(view.orchestrationPanelVisible.value).toBe(true)
    expect(view.orchestrationStatus.value).toBe('active')
    expect(view.activeAgent.value).toBe('planner')
    expect(view.visitedAgents.value).toContain('planner')
    expect(view.orchestrationEventFeed.value.map((item) => item.label)).toContain('正在分配任务')

    await promise

    expect(view.store.messages).toHaveLength(2)
    expect(view.store.messages[1].role).toBe('assistant')
    expect(view.store.messages[1].content).toBe('最终回复')
    expect(view.orchestrationPanelVisible.value).toBe(true)
    expect(view.orchestrationStatus.value).toBe('complete')
    expect(view.orchestrationEventFeed.value.at(-1)?.label).toBe('响应已生成')
    expect(view.activeAgent.value).toBe('planner')
    expect(view.store.messages).toHaveLength(2)
  })
})
