/**
 * SSE (Server-Sent Events) Handler 测试
 *
 * 测试 SSE 事件格式、订阅者管理、各类事件发送等功能
 */

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

// Mock dependencies before imports
const mockExists = vi.fn();
const mockSessionManager = {
  exists: mockExists,
};

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

// Import after mocking
import {
  emitEvent,
  broadcastEvent,
  emitStatusEvent,
  emitLogEvent,
  emitProgressEvent,
  emitFileChangeEvent,
  getSSEStats,
  handleSSE,
} from '../../src/sse.js';

describe('SSE Handler', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockExists.mockReturnValue(true);
  });

  describe('emitEvent - 发送事件', () => {
    it('无订阅者时不抛出错误', () => {
      expect(() => {
        emitEvent('non-existent-session', {
          event: 'test',
          data: { timestamp: Date.now(), payload: null },
        });
      }).not.toThrow();
    });
  });

  describe('broadcastEvent - 广播事件', () => {
    it('无订阅者时不抛出错误', () => {
      expect(() => {
        broadcastEvent({
          event: 'broadcast-test',
          data: { timestamp: Date.now(), payload: { message: 'hello' } },
        });
      }).not.toThrow();
    });
  });

  describe('emitStatusEvent - 发送状态事件', () => {
    it('调用时不抛出错误', () => {
      expect(() => {
        emitStatusEvent('session-1', 'processing', { step: 1, total: 5 });
      }).not.toThrow();
    });

    it('只传状态不传详情时不抛出错误', () => {
      expect(() => {
        emitStatusEvent('session-1', 'idle');
      }).not.toThrow();
    });
  });

  describe('emitLogEvent - 发送日志事件', () => {
    it('发送 info 级别日志', () => {
      expect(() => {
        emitLogEvent('session-1', 'info', 'Processing started');
      }).not.toThrow();
    });

    it('发送 warn 级别日志', () => {
      expect(() => {
        emitLogEvent('session-1', 'warn', 'Rate limit approaching');
      }).not.toThrow();
    });

    it('发送 error 级别日志', () => {
      expect(() => {
        emitLogEvent('session-1', 'error', 'Connection failed');
      }).not.toThrow();
    });
  });

  describe('emitProgressEvent - 发送进度事件', () => {
    it('发送进度（带消息）', () => {
      expect(() => {
        emitProgressEvent('session-1', 50, 'Half way done');
      }).not.toThrow();
    });

    it('发送进度（不带消息）', () => {
      expect(() => {
        emitProgressEvent('session-1', 100);
      }).not.toThrow();
    });

    it('发送 0% 进度', () => {
      expect(() => {
        emitProgressEvent('session-1', 0, 'Starting...');
      }).not.toThrow();
    });
  });

  describe('emitFileChangeEvent - 发送文件变更事件', () => {
    it('发送文件创建事件', () => {
      expect(() => {
        emitFileChangeEvent('session-1', 'created', '/path/to/new/file.ts');
      }).not.toThrow();
    });

    it('发送文件修改事件', () => {
      expect(() => {
        emitFileChangeEvent('session-1', 'modified', '/path/to/existing/file.ts');
      }).not.toThrow();
    });

    it('发送文件删除事件', () => {
      expect(() => {
        emitFileChangeEvent('session-1', 'deleted', '/path/to/removed/file.ts');
      }).not.toThrow();
    });
  });

  describe('getSSEStats - 获取统计信息', () => {
    it('无订阅者时返回 0', () => {
      const stats = getSSEStats();
      // 由于没有实际连接，应该至少有这些属性
      expect(stats).toHaveProperty('sessions');
      expect(stats).toHaveProperty('subscribers');
      expect(typeof stats.sessions).toBe('number');
      expect(typeof stats.subscribers).toBe('number');
    });

    it('初始状态统计为 0', () => {
      const stats = getSSEStats();
      expect(stats.sessions).toBe(0);
      expect(stats.subscribers).toBe(0);
    });
  });

  describe('事件格式化', () => {
    it('emitEvent 格式化带 event 字段的事件', () => {
      // 无订阅者时调用不会抛错，但内部会格式化
      emitEvent('test-session', {
        event: 'custom_event',
        data: { timestamp: 12345, payload: { key: 'value' } },
      });
      // 测试不抛错即为通过
    });

    it('emitEvent 格式化不带 event 字段的事件', () => {
      emitEvent('test-session', {
        data: { timestamp: 12345, payload: null },
      });
    });

    it('复杂 payload 数据正确序列化', () => {
      expect(() => {
        emitStatusEvent('session-1', 'processing', {
          nested: { deep: { value: [1, 2, 3] } },
          array: ['a', 'b', 'c'],
          number: 42,
          boolean: true,
          null: null,
        });
      }).not.toThrow();
    });
  });

  describe('handleSSE - SSE 路由处理', () => {
    it('会话不存在时返回 404', async () => {
      mockExists.mockReturnValue(false);

      const app = new Hono();
      app.get('/api/sessions/:id/events', handleSSE);

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

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

    it('会话存在时返回 SSE 流响应', async () => {
      mockExists.mockReturnValue(true);

      const app = new Hono();
      app.get('/api/sessions/:id/events', handleSSE);

      const res = await app.request('/api/sessions/valid-session/events');

      // SSE 流应该返回 200 状态码
      expect(res.status).toBe(200);
      // Content-Type 应该是 text/event-stream
      expect(res.headers.get('content-type')).toContain('text/event-stream');
    });
  });
});
