/**
 * 网络测试 - 测试WebSocket连接和消息传递
 */
import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest';
import { createServer } from 'http';
import { Server } from 'socket.io';
import { io as ioc, Socket as ClientSocket } from 'socket.io-client';
import { SOCKET_EVENTS } from '@gala/shared/constants';

describe('网络测试', () => {
  let httpServer: ReturnType<typeof createServer>;
  let io: Server;
  let clientSocket: ClientSocket;
  const TEST_PORT = 3099;

  beforeAll((done) => {
    httpServer = createServer();
    io = new Server(httpServer);

    // 模拟服务端事件处理
    io.on('connection', (socket) => {
      socket.on(SOCKET_EVENTS.CONNECTION_JOIN, (data, callback) => {
        if (typeof callback === 'function') {
          callback({
            success: true,
            userId: data.userId,
            state: { phase: 'voting' }
          });
        }
      });

      socket.on(SOCKET_EVENTS.CONNECTION_PING, () => {
        socket.emit(SOCKET_EVENTS.CONNECTION_PONG);
      });

      socket.on(SOCKET_EVENTS.VOTE_SUBMIT, (data, callback) => {
        if (typeof callback === 'function') {
          callback({ success: true, newCount: 1 });
        }
      });

      socket.on(SOCKET_EVENTS.SYNC_REQUEST, () => {
        socket.emit(SOCKET_EVENTS.SYNC_STATE, { phase: 'voting' });
      });
    });

    httpServer.listen(TEST_PORT, done);
  });

  afterEach(() => {
    if (clientSocket?.connected) {
      clientSocket.disconnect();
    }
  });

  afterAll(() => {
    io.close();
    httpServer.close();
  });

  describe('WebSocket连接', () => {
    it('应该能成功建立连接', (done) => {
      clientSocket = ioc(`http://localhost:${TEST_PORT}`);
      clientSocket.on('connect', () => {
        expect(clientSocket.connected).toBe(true);
        done();
      });
    });

    it('应该能正常断开连接', (done) => {
      clientSocket = ioc(`http://localhost:${TEST_PORT}`);
      clientSocket.on('connect', () => {
        clientSocket.disconnect();
      });
      clientSocket.on('disconnect', () => {
        expect(clientSocket.connected).toBe(false);
        done();
      });
    });

    it('断开后应该能重新连接', (done) => {
      clientSocket = ioc(`http://localhost:${TEST_PORT}`, {
        reconnection: true,
        reconnectionAttempts: 3,
      });

      let connectCount = 0;
      clientSocket.on('connect', () => {
        connectCount++;
        if (connectCount === 1) {
          clientSocket.disconnect();
          setTimeout(() => clientSocket.connect(), 100);
        } else {
          expect(connectCount).toBe(2);
          done();
        }
      });
    });
  });

  describe('心跳检测', () => {
    it('ping应该收到pong响应', (done) => {
      clientSocket = ioc(`http://localhost:${TEST_PORT}`);
      clientSocket.on('connect', () => {
        clientSocket.emit(SOCKET_EVENTS.CONNECTION_PING);
      });
      clientSocket.on(SOCKET_EVENTS.CONNECTION_PONG, () => {
        expect(true).toBe(true);
        done();
      });
    });
  });

  describe('加入房间', () => {
    it('应该能成功加入并收到确认', (done) => {
      clientSocket = ioc(`http://localhost:${TEST_PORT}`);
      clientSocket.on('connect', () => {
        clientSocket.emit(
          SOCKET_EVENTS.CONNECTION_JOIN,
          { userId: 'test_user', role: 'audience' },
          (response: any) => {
            expect(response.success).toBe(true);
            expect(response.userId).toBe('test_user');
            done();
          }
        );
      });
    });
  });

  describe('投票消息', () => {
    it('应该能发送投票并收到确认', (done) => {
      clientSocket = ioc(`http://localhost:${TEST_PORT}`);
      clientSocket.on('connect', () => {
        clientSocket.emit(
          SOCKET_EVENTS.VOTE_SUBMIT,
          { programId: 'prog_1', ticketType: 'creative' },
          (response: any) => {
            expect(response.success).toBe(true);
            expect(response.newCount).toBeDefined();
            done();
          }
        );
      });
    });
  });

  describe('状态同步', () => {
    it('请求同步应该收到状态', (done) => {
      clientSocket = ioc(`http://localhost:${TEST_PORT}`);
      clientSocket.on('connect', () => {
        clientSocket.emit(SOCKET_EVENTS.SYNC_REQUEST);
      });
      clientSocket.on(SOCKET_EVENTS.SYNC_STATE, (state: any) => {
        expect(state).toBeDefined();
        expect(state.phase).toBe('voting');
        done();
      });
    });
  });
});
