import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { createPinia, setActivePinia } from 'pinia'
import {
  fetchOpenClawAgents,
  fetchOpenClawCapabilities,
  openClawOverviewQueryOptions,
  projectOpenClawAgentNodes,
  type OpenClawOverviewDto,
} from '../src/api/openclawRuntime'
import { queryClient } from '../src/api/queryClient'
import { useAuthStore } from '../src/stores/auth'
import type {
  OpenClawAgent,
  OpenClawCapability,
  OpenClawCollection,
} from '../src/types/openclaw'

const now = '2026-07-31T10:00:00.000Z'

function collection<T>(items: T[]): OpenClawCollection<T> {
  return {
    state: 'ready',
    items,
    nextCursor: null,
    message: null,
    recovery: null,
    checkedAt: now,
  }
}

function overviewFixture(): OpenClawOverviewDto {
  return {
    connection: {
      state: 'connected',
      configured: true,
      credentialConfigured: true,
      connected: true,
      endpoint: 'ws://openclaw-gateway:18789',
      gatewayVersion: '2026.7.1',
      requiredVersion: '2026.7.1',
      versionPinned: true,
      versionMatches: true,
      protocolVersion: 4,
      grantedScopes: ['operator.read'],
      advertisedEvents: ['agent', 'task'],
      lastConnectedAt: now,
      lastEventAt: now,
      reconnectAttempts: 0,
      message: 'Connected',
      recovery: null,
      checkedAt: now,
      deviceId: 'nexus-test',
      pairingRequired: false,
      pairingRequestId: null,
    },
    capabilities: [],
    tasks: collection([{
      id: 'task-1',
      title: 'Prepare release',
      status: 'running',
      kind: 'agent',
      runtime: 'openclaw',
      agentId: 'iris',
      sessionKey: 'agent:iris:main',
      runId: 'run-1',
      flowId: null,
      parentTaskId: null,
      createdAt: now,
      startedAt: now,
      updatedAt: now,
      finishedAt: null,
      progress: 42,
      summary: 'Checks the release gates.',
      error: null,
      canCancel: true,
    }]),
    sessions: collection([{
      key: 'agent:iris:main',
      sessionId: 'session-1',
      agentId: 'iris',
      title: 'Release session',
      status: 'running',
      kind: 'agent',
      channel: null,
      model: 'openai/gpt-5.4',
      provider: 'openai',
      runId: 'run-1',
      updatedAt: now,
      inputTokens: 800,
      outputTokens: 400,
      totalTokens: 1_200,
      canAbort: true,
    }]),
    cronJobs: collection([]),
    approvals: collection([]),
    activity: collection([]),
    models: collection([{
      id: 'openai/gpt-5.4',
      name: 'GPT-5.4',
      provider: 'openai',
      configured: true,
      available: true,
      contextWindow: 1_000_000,
      reason: null,
    }]),
    agents: collection([{
      id: 'iris',
      name: 'Iris',
      description: 'Coordinates the team.',
      model: null,
      provider: 'openai',
      workspace: '/managed/agents/iris',
      status: 'ready',
    }]),
    generatedAt: now,
  }
}

function authenticate(): void {
  const auth = useAuthStore()
  auth.initialized = true
  auth.applySession({
    accessToken: 'runtime-access-token',
    expiresAt: '2026-07-31T12:00:00.000Z',
    user: {
      id: 'bao',
      email: 'bao@nexus.local',
      displayName: 'Bao',
      role: 'owner',
    },
  })
}

function pathOf(input: RequestInfo | URL): string {
  const raw = input instanceof Request ? input.url : String(input)
  return new URL(raw, 'http://localhost').pathname
}

beforeEach(() => {
  setActivePinia(createPinia())
  authenticate()
  queryClient.clear()
})

afterEach(() => {
  queryClient.clear()
  vi.unstubAllGlobals()
})

describe('shared OpenClaw runtime queries', () => {
  it('deduplicates simultaneous overview consumers at the authenticated boundary', async () => {
    const fetchMock = vi.fn(async () => new Response(JSON.stringify(overviewFixture()), {
      status: 200,
      headers: { 'Content-Type': 'application/json' },
    }))
    vi.stubGlobal('fetch', fetchMock)

    const options = openClawOverviewQueryOptions()
    const results = await Promise.all([
      queryClient.fetchQuery(options),
      queryClient.fetchQuery(options),
      queryClient.fetchQuery(options),
    ])

    expect(results.every(result => result.connection.connected)).toBe(true)
    expect(fetchMock).toHaveBeenCalledTimes(1)
    const [input, init] = fetchMock.mock.calls[0]!
    expect(pathOf(input)).toBe('/api/v1/openclaw/overview')
    expect(new Headers(init?.headers).get('Authorization')).toBe('Bearer runtime-access-token')
  })

  it('uses the dedicated capability and agent contracts', async () => {
    const capabilities: OpenClawCapability[] = [{
      id: 'agents-list',
      label: 'List agents',
      method: 'agents.list',
      requiredScope: 'operator.read',
      available: true,
      state: 'ready',
      reason: null,
    }]
    const agents: OpenClawCollection<OpenClawAgent> = collection([
      overviewFixture().agents.items[0]!,
    ])
    const fetchMock = vi.fn(async (input: RequestInfo | URL) => {
      const path = pathOf(input)
      return new Response(JSON.stringify(
        path.endsWith('/capabilities') ? capabilities : agents,
      ), {
        status: 200,
        headers: { 'Content-Type': 'application/json' },
      })
    })
    vi.stubGlobal('fetch', fetchMock)

    await expect(fetchOpenClawCapabilities()).resolves.toEqual(capabilities)
    await expect(fetchOpenClawAgents()).resolves.toEqual(agents)
    expect(fetchMock.mock.calls.map(call => pathOf(call[0]))).toEqual([
      '/api/v1/openclaw/capabilities',
      '/api/v1/openclaw/agents',
    ])
  })

  it('projects task, session, model and token state without a dashboard facade', () => {
    expect(projectOpenClawAgentNodes(overviewFixture())).toEqual([
      expect.objectContaining({
        id: 'iris',
        status: 'work',
        statusLabel: 'Arbeitet',
        task: 'Prepare release',
        progress: 42,
        model: 'openai/gpt-5.4',
        tokens: '1.2k',
      }),
    ])
  })
})
