/**
 * 清洁的WebSocket网关
 * 使用原生WebSocket，不依赖NestJS的WebSocket装饰器
 */

import { Injectable, Logger, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import * as WebSocket from 'ws';
import { ZulipService } from './zulip.service';
import { SessionManagerService } from './services/session_manager.service';

interface ExtendedWebSocket extends WebSocket {
  id: string;
  isAlive?: boolean;
  authenticated?: boolean;
  userId?: string;
  username?: string;
  sessionId?: string;
  currentMap?: string;
}

@Injectable()
export class CleanWebSocketGateway implements OnModuleInit, OnModuleDestroy {
  private server: WebSocket.Server;
  private readonly logger = new Logger(CleanWebSocketGateway.name);
  private clients = new Map<string, ExtendedWebSocket>();
  private mapRooms = new Map<string, Set<string>>(); // mapId -> Set<clientId>

  constructor(
    private readonly zulipService: ZulipService,
    private readonly sessionManager: SessionManagerService,
  ) {}

  async onModuleInit() {
    const port = 3001;
    
    this.server = new WebSocket.Server({ port });

    this.server.on('connection', (ws: ExtendedWebSocket) => {
      ws.id = this.generateClientId();
      ws.isAlive = true;
      ws.authenticated = false;
      
      this.clients.set(ws.id, ws);
      
      this.logger.log(`新的WebSocket连接: ${ws.id}`);

      ws.on('message', (data) => {
        try {
          const message = JSON.parse(data.toString());
          this.handleMessage(ws, message);
        } catch (error) {
          this.logger.error('解析消息失败', error);
          this.sendError(ws, '消息格式错误');
        }
      });

      ws.on('close', () => {
        this.logger.log(`WebSocket连接关闭: ${ws.id}`);
        this.cleanupClient(ws);
      });

      ws.on('error', (error) => {
        this.logger.error(`WebSocket错误: ${ws.id}`, error);
      });

      // 发送连接确认
      this.sendMessage(ws, {
        type: 'connected',
        message: '连接成功',
        socketId: ws.id
      });
    });

    this.logger.log(`WebSocket服务器启动成功，端口: ${port}`);
  }

  async onModuleDestroy() {
    if (this.server) {
      this.server.close();
      this.logger.log('WebSocket服务器已关闭');
    }
  }

  private async handleMessage(ws: ExtendedWebSocket, message: any) {
    this.logger.log(`收到消息: ${ws.id}`, message);

    const messageType = message.type || message.t;
    
    this.logger.log(`消息类型: ${messageType}`, { type: message.type, t: message.t });

    switch (messageType) {
      case 'login':
        await this.handleLogin(ws, message);
        break;
      case 'chat':
        await this.handleChat(ws, message);
        break;
      case 'position':
        await this.handlePositionUpdate(ws, message);
        break;
      default:
        this.logger.warn(`未知消息类型: ${messageType}`, message);
        this.sendError(ws, `未知消息类型: ${messageType}`);
    }
  }

  private async handleLogin(ws: ExtendedWebSocket, message: any) {
    try {
      if (!message.token) {
        this.sendError(ws, 'Token不能为空');
        return;
      }

      // 调用ZulipService进行登录
      const result = await this.zulipService.handlePlayerLogin({
        socketId: ws.id,
        token: message.token
      });

      if (result.success) {
        ws.authenticated = true;
        ws.userId = result.userId;
        ws.username = result.username;
        ws.sessionId = result.sessionId;
        ws.currentMap = 'whale_port'; // 默认地图

        // 加入默认地图房间
        this.joinMapRoom(ws.id, ws.currentMap);

        this.sendMessage(ws, {
          t: 'login_success',
          sessionId: result.sessionId,
          userId: result.userId,
          username: result.username,
          currentMap: ws.currentMap
        });

        this.logger.log(`用户登录成功: ${result.username} (${ws.id}) 进入地图: ${ws.currentMap}`);
      } else {
        this.sendMessage(ws, {
          t: 'login_error',
          message: result.error || '登录失败'
        });
      }
    } catch (error) {
      this.logger.error('登录处理失败', error);
      this.sendError(ws, '登录处理失败');
    }
  }

  private async handleChat(ws: ExtendedWebSocket, message: any) {
    try {
      if (!ws.authenticated) {
        this.sendError(ws, '请先登录');
        return;
      }

      if (!message.content) {
        this.sendError(ws, '消息内容不能为空');
        return;
      }

      // 调用ZulipService发送消息
      const result = await this.zulipService.sendChatMessage({
        socketId: ws.id,
        content: message.content,
        scope: message.scope || 'local'
      });

      if (result.success) {
        this.sendMessage(ws, {
          t: 'chat_sent',
          messageId: result.messageId,
          message: '消息发送成功'
        });

        // 广播消息给其他用户（根据scope决定范围）
        if (message.scope === 'global') {
          // 全局消息：广播给所有已认证用户
          this.broadcastMessage({
            t: 'chat_render',
            from: ws.username,
            txt: message.content,
            bubble: true,
            scope: 'global'
          }, ws.id);
        } else {
          // 本地消息：只广播给同一地图的用户
          this.broadcastToMap(ws.currentMap, {
            t: 'chat_render',
            from: ws.username,
            txt: message.content,
            bubble: true,
            scope: 'local',
            mapId: ws.currentMap
          }, ws.id);
        }

        this.logger.log(`消息发送成功: ${ws.username} -> ${message.content}`);
      } else {
        this.sendMessage(ws, {
          t: 'chat_error',
          message: result.error || '消息发送失败'
        });
      }
    } catch (error) {
      this.logger.error('聊天处理失败', error);
      this.sendError(ws, '聊天处理失败');
    }
  }

  private async handlePositionUpdate(ws: ExtendedWebSocket, message: any) {
    try {
      if (!ws.authenticated) {
        this.sendError(ws, '请先登录');
        return;
      }

      // 简单的位置更新处理，这里可以添加更多逻辑
      this.logger.log(`位置更新: ${ws.username} -> (${message.x}, ${message.y}) 在 ${message.mapId}`);
      
      // 如果用户切换了地图，更新房间
      if (ws.currentMap !== message.mapId) {
        this.leaveMapRoom(ws.id, ws.currentMap);
        this.joinMapRoom(ws.id, message.mapId);
        ws.currentMap = message.mapId;
        
        this.logger.log(`用户 ${ws.username} 切换到地图: ${message.mapId}`);
      }
      
      // 广播位置更新给同一地图的其他用户
      this.broadcastToMap(message.mapId, {
        t: 'position_update',
        userId: ws.userId,
        username: ws.username,
        x: message.x,
        y: message.y,
        mapId: message.mapId
      }, ws.id);

    } catch (error) {
      this.logger.error('位置更新处理失败', error);
      this.sendError(ws, '位置更新处理失败');
    }
  }

  private sendMessage(ws: ExtendedWebSocket, data: any) {
    if (ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify(data));
    }
  }

  private sendError(ws: ExtendedWebSocket, message: string) {
    this.sendMessage(ws, {
      type: 'error',
      message: message
    });
  }

  private broadcastMessage(data: any, excludeId?: string) {
    this.clients.forEach((client, id) => {
      if (id !== excludeId && client.authenticated) {
        this.sendMessage(client, data);
      }
    });
  }

  private broadcastToMap(mapId: string, data: any, excludeId?: string) {
    const room = this.mapRooms.get(mapId);
    if (!room) return;

    room.forEach(clientId => {
      if (clientId !== excludeId) {
        const client = this.clients.get(clientId);
        if (client && client.authenticated) {
          this.sendMessage(client, data);
        }
      }
    });
  }

  private joinMapRoom(clientId: string, mapId: string) {
    if (!this.mapRooms.has(mapId)) {
      this.mapRooms.set(mapId, new Set());
    }
    this.mapRooms.get(mapId).add(clientId);
    
    this.logger.log(`客户端 ${clientId} 加入地图房间: ${mapId}`);
  }

  private leaveMapRoom(clientId: string, mapId: string) {
    const room = this.mapRooms.get(mapId);
    if (room) {
      room.delete(clientId);
      if (room.size === 0) {
        this.mapRooms.delete(mapId);
      }
      this.logger.log(`客户端 ${clientId} 离开地图房间: ${mapId}`);
    }
  }

  private cleanupClient(ws: ExtendedWebSocket) {
    // 从地图房间中移除
    if (ws.currentMap) {
      this.leaveMapRoom(ws.id, ws.currentMap);
    }
    
    // 从客户端列表中移除
    this.clients.delete(ws.id);
  }

  private generateClientId(): string {
    return `ws_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  // 公共方法供其他服务调用
  public getConnectionCount(): number {
    return this.clients.size;
  }

  public getAuthenticatedConnectionCount(): number {
    return Array.from(this.clients.values()).filter(client => client.authenticated).length;
  }

  public getMapPlayerCounts(): Record<string, number> {
    const counts: Record<string, number> = {};
    this.mapRooms.forEach((clients, mapId) => {
      counts[mapId] = clients.size;
    });
    return counts;
  }

  public getMapPlayers(mapId: string): string[] {
    const room = this.mapRooms.get(mapId);
    if (!room) return [];
    
    const players: string[] = [];
    room.forEach(clientId => {
      const client = this.clients.get(clientId);
      if (client && client.authenticated && client.username) {
        players.push(client.username);
      }
    });
    return players;
  }
}