/**
 * Sessions Route 测试
 *
 * 测试会话管理 REST API 端点
 *
 * 注意：消息存储已移至 Core 层，GET /sessions/:id/messages 从 Core Storage 读取
 */

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

// Mock storage interface
const mockLoadSession = vi.fn();

// Use vi.hoisted to create mocks before vi.mock is hoisted
const { mockList, mockCreate, mockGet, mockExists, mockDelete, mockGetStorage, mockGetProjectId } = vi.hoisted(() => ({
  mockList: vi.fn(),
  mockCreate: vi.fn(),
  mockGet: vi.fn(),
  mockExists: vi.fn(),
  mockDelete: vi.fn(),
  mockGetStorage: vi.fn(),
  mockGetProjectId: vi.fn(),
}));

vi.mock('../../../src/session/manager.js', () => ({
  getSessionManager: vi.fn(() => ({
    list: mockList,
    create: mockCreate,
    get: mockGet,
    exists: mockExists,
    delete: mockDelete,
    getStorage: mockGetStorage,
    getProjectId: mockGetProjectId,
  })),
}));

import { sessionsRouter } from '../../../src/routes/sessions.js';

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

describe('Sessions Route', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockGetStorage.mockReturnValue({
      loadSession: mockLoadSession,
    });
    mockGetProjectId.mockReturnValue('default-project');
  });

  describe('GET /sessions - 列出会话', () => {
    it('返回会话列表', async () => {
      const sessions = [
        { id: 'session-1', name: 'Test 1', status: 'idle', createdAt: 1000, updatedAt: 1000 },
        { id: 'session-2', name: 'Test 2', status: 'active', createdAt: 2000, updatedAt: 2000 },
      ];
      mockList.mockReturnValue(sessions);

      const res = await app.request('/sessions');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data).toEqual(sessions);
    });

    it('空列表返回空数组', async () => {
      mockList.mockReturnValue([]);

      const res = await app.request('/sessions');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data).toEqual([]);
    });
  });

  describe('POST /sessions - 创建会话', () => {
    it('创建新会话', async () => {
      const newSession = {
        id: 'new-session',
        name: 'My Session',
        status: 'idle',
        createdAt: Date.now(),
        updatedAt: Date.now(),
      };
      mockCreate.mockResolvedValue(newSession);

      const res = await app.request('/sessions', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name: 'My Session' }),
      });
      const json = await res.json();

      expect(res.status).toBe(201);
      expect(json.success).toBe(true);
      expect(json.data).toEqual(newSession);
    });

    it('无效输入返回 400', async () => {
      const res = await app.request('/sessions', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: 'invalid json',
      });
      const json = await res.json();

      expect(res.status).toBe(400);
      expect(json.success).toBe(false);
    });
  });

  describe('GET /sessions/:id - 获取单个会话', () => {
    it('返回存在的会话', async () => {
      const session = { id: 'session-1', name: 'Test', status: 'idle' };
      mockGet.mockReturnValue(session);

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

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data).toEqual(session);
    });

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

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

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

  describe('DELETE /sessions/:id - 删除会话', () => {
    it('删除存在的会话', async () => {
      mockExists.mockReturnValue(true);
      mockDelete.mockResolvedValue(true);

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

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(mockDelete).toHaveBeenCalledWith('session-1');
    });

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

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

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

  describe('GET /sessions/:id/messages - 获取消息', () => {
    it('返回会话消息（从 Core Storage 读取）', async () => {
      const messages = [
        { role: 'user', content: 'Hello' },
        { role: 'assistant', content: [{ type: 'tool-call', toolName: 'read_file' }] },
        { role: 'user', content: [{ type: 'tool-result', toolCallId: 'call-1' }] },
        { role: 'assistant', content: 'Hi!' },
      ];
      mockExists.mockReturnValue(true);
      mockLoadSession.mockResolvedValue({
        id: 'session-1',
        messages,
      });

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

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data).toEqual(messages);
      expect(mockGetStorage).toHaveBeenCalled();
      expect(mockGetProjectId).toHaveBeenCalledWith('session-1');
    });

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

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

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

    it('空消息返回空数组', async () => {
      mockExists.mockReturnValue(true);
      mockLoadSession.mockResolvedValue({
        id: 'session-1',
        messages: [],
      });

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

      expect(res.status).toBe(200);
      expect(json.data).toEqual([]);
    });

    it('Storage 不可用时返回空数组', async () => {
      mockExists.mockReturnValue(true);
      mockGetStorage.mockReturnValue(null);

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

      expect(res.status).toBe(200);
      expect(json.data).toEqual([]);
    });

    it('Session 数据不存在时返回空数组', async () => {
      mockExists.mockReturnValue(true);
      mockLoadSession.mockResolvedValue(null);

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

      expect(res.status).toBe(200);
      expect(json.data).toEqual([]);
    });
  });
});
