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

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

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

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

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

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

describe('Sessions Route', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    // Mock dynamic import of @ai-assistant/core
    vi.doMock('@ai-assistant/core', () => ({
      MessageStorage: {
        listBySession: mockMessageListBySession,
      },
      PartStorage: {
        getByIds: mockPartGetByIds,
      },
    }));
  });

  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: 'session-1',
        name: 'New 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: 'New Session' }),
      });
      const json = await res.json();

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

    it('创建会话（无需必填字段）', async () => {
      // CreateSessionInputSchema 的所有字段都是可选的，任何对象都是有效的
      const newSession = {
        id: 'session-2',
        name: undefined,
        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({}),
      });
      const json = await res.json();

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

  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('不存在的会话返回 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);
      // Mock empty messages (Core Storage will fail to import in tests, returning empty array)

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

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      // In test environment, dynamic import fails and returns empty array
      expect(json.data).toEqual([]);
    });

    it('Core Storage 错误时返回空数组', async () => {
      mockExists.mockReturnValue(true);
      // The route handles errors gracefully

      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([]);
    });
  });
});
