/**
 * Context Route 测试
 *
 * 测试上下文压缩 REST API 端点
 */

import { describe, it, expect, beforeEach, vi } from 'vitest';
import { Hono } from 'hono';

// Use vi.hoisted to create mocks before vi.mock is hoisted
const { mockExists, mockGetContextUsage, mockCompressContext } = vi.hoisted(() => ({
  mockExists: vi.fn(),
  mockGetContextUsage: vi.fn(),
  mockCompressContext: vi.fn(),
}));

vi.mock('../../../src/session/manager.js', () => ({
  getSessionManager: vi.fn(() => ({
    exists: mockExists,
  })),
}));

vi.mock('../../../src/agent/adapter.js', () => ({
  getContextUsage: mockGetContextUsage,
  compressContext: mockCompressContext,
}));

import { contextRouter } from '../../../src/routes/context.js';

// Create test app
const app = new Hono();
app.route('', contextRouter);

describe('Context Route', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('GET /sessions/:id/context - 获取上下文使用情况', () => {
    it('返回上下文使用信息', async () => {
      mockExists.mockReturnValue(true);
      mockGetContextUsage.mockReturnValue({
        input: 50000,
        contextLimit: 200000,
        available: 150000,
        usagePercent: 25,
        formatted: '50K/150K (25%)',
        shouldCompress: false,
      });

      const res = await app.request('/sessions/session-1/context');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data.input).toBe(50000);
      expect(json.data.usagePercent).toBe(25);
    });

    it('会话不存在返回 404', async () => {
      mockExists.mockReturnValue(false);

      const res = await app.request('/sessions/non-existent/context');
      const json = await res.json();

      expect(res.status).toBe(404);
      expect(json.success).toBe(false);
      expect(json.error).toBe('Session not found');
    });

    it('Agent 未初始化时返回默认值', async () => {
      mockExists.mockReturnValue(true);
      mockGetContextUsage.mockReturnValue(null);

      const res = await app.request('/sessions/session-1/context');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data.input).toBe(0);
      expect(json.data.usagePercent).toBe(0);
      expect(json.data.shouldCompress).toBe(false);
    });
  });

  describe('POST /sessions/:id/compress - 触发手动压缩', () => {
    it('成功压缩上下文', async () => {
      mockExists.mockReturnValue(true);
      mockCompressContext.mockResolvedValue({
        type: 'summarize',
        freedTokens: 10000,
        newTokenCount: 40000,
      });

      const res = await app.request('/sessions/session-1/compress', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ force: false }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data.type).toBe('summarize');
      expect(json.data.freedTokens).toBe(10000);
    });

    it('强制压缩', async () => {
      mockExists.mockReturnValue(true);
      mockCompressContext.mockResolvedValue({
        type: 'summarize',
        freedTokens: 20000,
        newTokenCount: 30000,
      });

      const res = await app.request('/sessions/session-1/compress', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ force: true }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(mockCompressContext).toHaveBeenCalledWith('session-1', true);
    });

    it('无请求体时默认不强制压缩', async () => {
      mockExists.mockReturnValue(true);
      mockCompressContext.mockResolvedValue({
        type: 'prune',
        freedTokens: 5000,
      });

      const res = await app.request('/sessions/session-1/compress', {
        method: 'POST',
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(mockCompressContext).toHaveBeenCalledWith('session-1', false);
    });

    it('会话不存在返回 404', async () => {
      mockExists.mockReturnValue(false);

      const res = await app.request('/sessions/non-existent/compress', {
        method: 'POST',
      });
      const json = await res.json();

      expect(res.status).toBe(404);
      expect(json.success).toBe(false);
      expect(json.error).toBe('Session not found');
    });

    it('Agent 未初始化返回 400', async () => {
      mockExists.mockReturnValue(true);
      mockCompressContext.mockResolvedValue(null);

      const res = await app.request('/sessions/session-1/compress', {
        method: 'POST',
      });
      const json = await res.json();

      expect(res.status).toBe(400);
      expect(json.success).toBe(false);
      expect(json.error).toBe('Agent not initialized for this session');
    });

    it('压缩失败返回 500', async () => {
      mockExists.mockReturnValue(true);
      mockCompressContext.mockRejectedValue(new Error('Compression failed'));

      const res = await app.request('/sessions/session-1/compress', {
        method: 'POST',
      });
      const json = await res.json();

      expect(res.status).toBe(500);
      expect(json.success).toBe(false);
      expect(json.error).toBe('Compression failed');
    });
  });
});
