import type { AguiEvent } from '../../shared/agent-agui/client';

import { EventType } from '@ag-ui/client';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

import { easyFlowAguiCustomEvent } from '../../shared/agent-agui/custom-events';
import { useAgentTryoutRawRounds } from './useAgentTryoutRawRounds';

function event(value: AguiEvent) {
  return value;
}

describe('useAgentTryoutRawRounds', () => {
  beforeEach(() => {
    sessionStorage.clear();
  });

  afterEach(() => {
    vi.useRealTimers();
  });

  it('按原生 AG-UI 事件重建思考和正文', () => {
    const store = useAgentTryoutRawRounds({
      mode: 'draft',
      sessionId: 'standard-events',
    });
    const roundId = store.createRound('问题');
    store.recordEvent(
      roundId,
      event({
        delta: '先思考',
        messageId: 'reasoning-1',
        type: EventType.REASONING_MESSAGE_CONTENT,
      }),
    );
    store.recordEvent(
      roundId,
      event({
        delta: '回答',
        messageId: 'assistant-1',
        type: EventType.TEXT_MESSAGE_CONTENT,
      }),
    );
    store.recordEvent(
      roundId,
      event({
        runId: 'run-1',
        threadId: 'standard-events',
        type: EventType.RUN_FINISHED,
      }),
    );

    const messages = store
      .buildTimelineItems()
      .filter((item) => item.type === 'message');
    expect(messages).toHaveLength(2);
    expect(JSON.stringify(messages)).toContain('先思考');
    expect(JSON.stringify(messages)).toContain('回答');
  });

  it('使用原始轮次时间重放已完成处理时长', () => {
    vi.useFakeTimers();
    vi.setSystemTime(1000);
    const store = useAgentTryoutRawRounds({
      mode: 'draft',
      sessionId: 'stable-duration',
    });
    const roundId = store.createRound('问题');
    store.recordEvent(
      roundId,
      event({
        runId: roundId,
        threadId: 'stable-duration',
        type: EventType.RUN_STARTED,
      }),
    );
    vi.setSystemTime(19_000);
    store.recordEvent(
      roundId,
      event({
        delta: '回答',
        messageId: 'assistant-1',
        type: EventType.TEXT_MESSAGE_CONTENT,
      }),
    );
    store.recordEvent(
      roundId,
      event({
        runId: roundId,
        threadId: 'stable-duration',
        type: EventType.RUN_FINISHED,
      }),
    );

    const turnItems = store
      .buildTimelineItems()
      .filter(
        (item) =>
          item.roundId === roundId &&
          !(item.type === 'message' && item.role === 'user'),
      );
    expect(turnItems.length).toBeGreaterThan(0);
    expect(turnItems.every((item) => item.turnStartedAt === 1000)).toBe(true);
    expect(turnItems.every((item) => item.turnFinishedAt === 19_000)).toBe(
      true,
    );
  });

  it('持久化并恢复 EasyFlow 自定义引用事件', () => {
    const sessionId = 'custom-citations';
    const store = useAgentTryoutRawRounds({ mode: 'draft', sessionId });
    const roundId = store.createRound('查知识库');
    store.recordEvent(
      roundId,
      event({
        name: easyFlowAguiCustomEvent.knowledgeCitations,
        type: EventType.CUSTOM,
        value: {
          items: [{ chunkContent: '知识库原文', id: 'chunk-1' }],
        },
      }),
    );
    store.flush();

    const restored = useAgentTryoutRawRounds({ mode: 'draft', sessionId });
    expect(
      restored
        .buildTimelineItems()
        .some(
          (item) =>
            item.type === 'message' && Boolean(item.knowledgeItems?.length),
        ),
    ).toBe(true);
  });

  it('按工具调用 ID 合并标准工具参数与结果', () => {
    const store = useAgentTryoutRawRounds({
      mode: 'draft',
      sessionId: 'tool-events',
    });
    const roundId = store.createRound('调用工具');
    for (const item of [
      event({
        toolCallId: 'call-1',
        toolCallName: 'calculator',
        type: EventType.TOOL_CALL_START,
      }),
      event({
        delta: '{"value":1}',
        toolCallId: 'call-1',
        type: EventType.TOOL_CALL_ARGS,
      }),
      event({
        content: '2',
        messageId: 'tool-result-1',
        role: 'tool',
        toolCallId: 'call-1',
        type: EventType.TOOL_CALL_RESULT,
      }),
    ]) {
      store.recordEvent(roundId, item);
    }

    expect(
      store.buildTimelineItems().find((item) => item.type === 'tool'),
    ).toMatchObject({
      input: { value: 1 },
      output: '2',
      status: 'success',
      toolCallId: 'call-1',
    });
  });

  it('审批缓存仅保存不透明 approvalId', () => {
    const store = useAgentTryoutRawRounds({
      mode: 'draft',
      sessionId: 'approval-events',
    });
    const roundId = store.createRound('审批工具');
    store.recordEvent(
      roundId,
      event({
        name: easyFlowAguiCustomEvent.toolApprovalRequired,
        type: EventType.CUSTOM,
        value: {
          approvalId: 'approval-public',
          toolCallId: 'call-approval',
          toolName: 'dangerous_tool',
        },
      }),
    );
    store.flush();

    const serialized = JSON.stringify(store.currentVariant(roundId));
    expect(serialized).toContain('approval-public');
    expect(serialized).not.toContain('resumeToken');
    const tool = store
      .buildTimelineItems()
      .find((item) => item.type === 'tool');
    expect(tool?.type === 'tool' && tool.approval?.approvalId).toBe(
      'approval-public',
    );
  });

  it('压缩连续标准文本增量且刷新内容一致', () => {
    const sessionId = 'stream-compaction';
    const store = useAgentTryoutRawRounds({ mode: 'draft', sessionId });
    const roundId = store.createRound('你好');
    for (const delta of ['你', '好', '，', '世界']) {
      store.recordEvent(
        roundId,
        event({
          delta,
          messageId: 'assistant-1',
          type: EventType.TEXT_MESSAGE_CONTENT,
        }),
      );
    }
    store.flush();

    expect(store.currentVariant(roundId)?.runtimeEvents).toHaveLength(1);
    const restored = useAgentTryoutRawRounds({ mode: 'draft', sessionId });
    expect(JSON.stringify(restored.buildTimelineItems())).toContain(
      '你好，世界',
    );
  });

  it('记录 SDK 或 Vue 代理事件时转换为可持久化 JSON 数据', () => {
    const store = useAgentTryoutRawRounds({
      mode: 'draft',
      sessionId: 'proxied-event',
    });
    const roundId = store.createRound('代理事件');
    const proxiedEvent = new Proxy(
      event({
        delta: '代理响应',
        messageId: 'assistant-proxy',
        type: EventType.TEXT_MESSAGE_CONTENT,
      }),
      {},
    );

    expect(() => store.recordEvent(roundId, proxiedEvent)).not.toThrow();
    store.flush();
    expect(JSON.stringify(store.buildTimelineItems())).toContain('代理响应');
  });

  it('rUN_ERROR 终态立即持久化为失败轮次', () => {
    const sessionId = 'terminal-error';
    const store = useAgentTryoutRawRounds({ mode: 'draft', sessionId });
    const roundId = store.createRound('失败测试');
    store.recordEvent(
      roundId,
      event({
        message: '调用失败',
        runId: 'run-1',
        threadId: sessionId,
        type: EventType.RUN_ERROR,
      }),
    );

    const restored = useAgentTryoutRawRounds({ mode: 'draft', sessionId });
    expect(restored.currentVariant(roundId)?.status).toBe('error');
    expect(JSON.stringify(restored.buildTimelineItems())).toContain('调用失败');
  });

  it('刷新后保留运行标识并可重置当前变体进行权威重放', () => {
    const sessionId = 'resume-running';
    const store = useAgentTryoutRawRounds({ mode: 'draft', sessionId });
    const roundId = store.createRound('长回答');
    store.bindRun(roundId, 'run-resume');
    store.recordEvent(
      roundId,
      event({
        delta: '刷新前片段',
        messageId: 'assistant-1',
        type: EventType.TEXT_MESSAGE_CONTENT,
      }),
    );
    store.flush();

    const restored = useAgentTryoutRawRounds({ mode: 'draft', sessionId });
    expect(restored.recoverableRun()).toEqual(
      expect.objectContaining({
        roundId,
        runId: 'run-resume',
      }),
    );

    restored.resetRuntimeEvents(roundId);
    expect(restored.currentVariant(roundId)?.runtimeEvents).toEqual([]);
    expect(restored.currentVariant(roundId)?.status).toBe('running');
  });

  it('不恢复终态后超过二十四小时的草稿影子记录', () => {
    vi.useFakeTimers();
    vi.setSystemTime(2 * 24 * 60 * 60 * 1000);
    const sessionId = 'expired-draft';
    sessionStorage.setItem(
      `easyflow:agent-tryout-raw-rounds:draft:${sessionId}`,
      JSON.stringify({
        rounds: [
          {
            createdAt: 1,
            prompt: '过期问题',
            roundId: 'expired-round',
            selectedVariantIndex: 1,
            status: 'completed',
            updatedAt: 1,
            variants: [
              {
                createdAt: 1,
                runId: 'run-expired',
                runtimeEvents: [],
                status: 'completed',
                updatedAt: 1,
                variantIndex: 1,
              },
            ],
          },
        ],
        sessionId,
        version: 4,
      }),
    );

    const restored = useAgentTryoutRawRounds({ mode: 'draft', sessionId });

    expect(restored.recoverableRun()).toBeUndefined();
    expect(restored.buildTimelineItems()).toEqual([]);
  });

  it('运行中影子超过二十四小时仍保留到服务端确认终态', () => {
    vi.useFakeTimers();
    vi.setSystemTime(2 * 24 * 60 * 60 * 1000);
    const sessionId = 'old-running-draft';
    sessionStorage.setItem(
      `easyflow:agent-tryout-raw-rounds:draft:${sessionId}`,
      JSON.stringify({
        rounds: [
          {
            createdAt: 1,
            prompt: '仍在运行的问题',
            roundId: 'old-running-round',
            selectedVariantIndex: 1,
            status: 'running',
            updatedAt: 1,
            variants: [
              {
                createdAt: 1,
                runId: 'run-old-running',
                runtimeEvents: [],
                status: 'running',
                updatedAt: 1,
                variantIndex: 1,
              },
            ],
          },
        ],
        sessionId,
        version: 4,
      }),
    );

    const restored = useAgentTryoutRawRounds({ mode: 'draft', sessionId });

    expect(restored.recoverableRun()).toEqual(
      expect.objectContaining({
        roundId: 'old-running-round',
        runId: 'run-old-running',
      }),
    );
  });
});
