// server/websocket/minesweeperSocket.ts
import { Server as SocketIOServer } from 'socket.io';
import { Server as HTTPServer } from 'http';
import dotenv from 'dotenv';

// 加载环境变量
dotenv.config();

interface Cell {
  isMine: boolean;
  isRevealed: boolean;
  isFlagged: boolean;
  neighborMines: number;
  isExploded?: boolean;
}

interface GameRoom {
  roomId: string;
  playerId: string;
  board: Cell[][];
  difficulty: string;
  spectators: Set<string>;
  highlightedCells: Set<string>; // 存储需要闪烁的格子坐标 "row,col"
  invitePlayMode: boolean; // 是否邀请同玩模式
}

// 存储所有游戏房间
const gameRooms = new Map<string, GameRoom>();

// 获取 WebSocket 路径前缀 - 与客户端保持一致
function getSocketIoPath() {
  const envApiUrl = process.env.REACT_APP_API_BASE_URL;
  
  console.log('[Socket.IO Path Config] REACT_APP_API_BASE_URL:', envApiUrl);
  console.log('[Socket.IO Path Config] NODE_ENV:', process.env.NODE_ENV);
  
  if (!envApiUrl || envApiUrl.trim() === '') {
    // 如果没有设置环境变量，根据 NODE_ENV 决定
    const path = process.env.NODE_ENV === 'production' ? '/api/socket.io' : '/socket.io';
    console.log('[Socket.IO Path Config] Using default path:', path);
    return path;
  }
  
  // 根据Nginx转发规则调整生产环境路径
  // Nginx转发到 http://localhost:5001/api/socket.io/，所以后端应该接受 /api/socket.io
  if (process.env.NODE_ENV === 'production') {
    console.log('[Socket.IO Path Config] Production mode, Nginx配置');
    console.log('[Socket.IO Path Config] Frontend sends: /api/api/socket.io');
    console.log('[Socket.IO Path Config] Nginx location = /api/api/socket.io/');
    console.log('[Socket.IO Path Config] Nginx proxy_pass: http://localhost:5001/api/socket.io/');
    console.log('[Socket.IO Path Config] Backend should accept: /api/socket.io');
    // 使用 /api/socket.io 路径匹配Nginx转发结果
    return '/api/socket.io';
  }
  
  // 如果是完整 URL，检查是否包含路径
  if (envApiUrl.startsWith('http://') || envApiUrl.startsWith('https://')) {
    const urlObj = new URL(envApiUrl);
    // 如果原始 URL 包含路径，将其作为前缀
    if (urlObj.pathname && urlObj.pathname !== '/') {
      const path = `${urlObj.pathname}/socket.io`;
      console.log('[Socket.IO Path Config] From URL pathname:', path);
      return path;
    }
  }
  
  // 如果是相对路径（如 /api），将其作为前缀
  if (envApiUrl.startsWith('/')) {
    const path = `${envApiUrl}/socket.io`;
    console.log('[Socket.IO Path Config] From relative path:', path);
    return path;
  }
  
  const path = '/socket.io';
  console.log('[Socket.IO Path Config] Using fallback path:', path);
  return path;
}

export function setupMinesweeperSocket(httpServer: HTTPServer) {
  // 生产环境支持多种可能的路径，通过请求检测来确定
  const possiblePaths = ['/api/socket.io', '/socket.io'];
  const socketIoPath = getSocketIoPath();
  console.log('[Socket.IO] Socket.IO 路径配置:', socketIoPath);
  console.log('[Socket.IO] 支持的可能路径:', possiblePaths);
  console.log('[Socket.IO] HTTP Server listening on port:', httpServer.address());
  
  const io = new SocketIOServer(httpServer, {
    path: socketIoPath, // 使用最常见的路径作为配置
    cors: {
      origin: "*",
      methods: ["GET", "POST"]
    },
    allowEIO3: true,
    transports: ['polling', 'websocket']
  });

  // 添加底层HTTP请求日志中间件
  io.engine.on('initial_headers', (headers, req) => {
    console.log('[Socket.IO Engine] === INITIAL HEADERS ===');
    console.log('[Socket.IO Engine] Method:', req.method);
    console.log('[Socket.IO Engine] URL:', req.url);
    console.log('[Socket.IO Engine] Headers:', JSON.stringify(req.headers, null, 2));
    console.log('[Socket.IO Engine] Query:', req.url ? req.url.split('?')[1] : 'N/A');
    console.log('[Socket.IO Engine] ========================');
  });

  io.engine.on('headers', (headers, req) => {
    console.log('[Socket.IO Engine] === RESPONSE HEADERS ===');
    console.log('[Socket.IO Engine] Status:', headers.status || 200);
    console.log('[Socket.IO Engine] Headers:', JSON.stringify(headers, null, 2));
    console.log('[Socket.IO Engine] ========================');
  });

  io.on('connection', (socket) => {
    console.log('[Socket.IO] >>> CONNECTION ESTABLISHED <<<');
    console.log('[Socket.IO] 用户连接:', socket.id);
    console.log('[Socket.IO] 握手耗时:', Date.now() - (socket.handshake.time || Date.now()), 'ms');
    console.log('[Socket.IO] 握手 URL:', socket.handshake.url);
    console.log('[Socket.IO] 握手查询参数:', socket.handshake.query);
    console.log('[Socket.IO] 握手 Origin:', socket.handshake.headers.origin);
    console.log('[Socket.IO] 握手 Referer:', socket.handshake.headers.referer);
    console.log('[Socket.IO] 握手 User-Agent:', socket.handshake.headers['user-agent']);
    console.log('[Socket.IO] 握手 Host:', socket.handshake.headers.host);
    console.log('[Socket.IO] 配置的 Socket.IO 路径:', socketIoPath);
    
    // 详细路径分析 - 规范化路径比较（处理末尾斜杠差异）
    const reqPath = socket.handshake.url ? socket.handshake.url.split('?')[0] : 'N/A';
    const normalizedReqPath = reqPath.replace(/\/$/, ''); // 移除末尾斜杠
    const normalizedConfigPath = socketIoPath.replace(/\/$/, ''); // 移除末尾斜杠
    
    console.log('[Socket.IO] 路径分析:');
    console.log('  - 原始请求路径:', reqPath);
    console.log('  - 规范化请求路径:', normalizedReqPath);
    console.log('  - 配置路径:', socketIoPath);
    console.log('  - 规范化配置路径:', normalizedConfigPath);
    console.log('  - 严格相等:', reqPath === socketIoPath);
    console.log('  - 规范化后相等:', normalizedReqPath === normalizedConfigPath);
    console.log('  - 请求路径.endsWith(配置路径):', reqPath.endsWith(socketIoPath));
    console.log('  - 规范化请求.endsWith(规范化配置):', normalizedReqPath.endsWith(normalizedConfigPath));
    
    // 使用规范化路径进行比较
    if (normalizedReqPath !== normalizedConfigPath) {
      console.warn(`[Socket.IO] ⚠️  警告: 请求路径与配置路径不匹配!`);
      console.warn(`[Socket.IO]    原始请求: ${reqPath}`);
      console.warn(`[Socket.IO]    规范化请求: ${normalizedReqPath}`);
      console.warn(`[Socket.IO]    配置路径: ${socketIoPath}`);
      console.warn(`[Socket.IO]    规范化配置: ${normalizedConfigPath}`);
      console.warn(`[Socket.IO]    差异: ${reqPath.replace(socketIoPath, '【配置路径】')}`);
    }

    // 创建游戏房间（玩家创建）
    socket.on('create-room', (data: { difficulty: string; roomId?: string; invitePlayMode?: boolean }) => {
      const roomId = data.roomId || generateRoomId();
      const room: GameRoom = {
        roomId,
        playerId: socket.id,
        board: [],
        difficulty: data.difficulty,
        spectators: new Set(),
        highlightedCells: new Set(),
        invitePlayMode: data.invitePlayMode || false
      };
      
      gameRooms.set(roomId, room);
      socket.join(roomId);
      
      console.log(`[Socket.IO] 房间创建: ${roomId}, 玩家: ${socket.id}, 邀请同玩模式: ${room.invitePlayMode}`);
      socket.emit('room-created', { roomId });
    });

    // 旁观者加入房间
    socket.on('join-spectate', (data: { roomId: string }) => {
      const room = gameRooms.get(data.roomId);
      
      if (!room) {
        socket.emit('error', { message: '房间不存在' });
        return;
      }

      room.spectators.add(socket.id);
      socket.join(data.roomId);
      
      console.log(`旁观者加入: ${socket.id} -> 房间: ${data.roomId}`);
      
      // 发送当前游戏状态给旁观者
      socket.emit('game-state', {
        board: room.board,
        difficulty: room.difficulty
      });
    });

    // 获取房间信息
    socket.on('get-room-info', (data: { roomId: string }) => {
      console.log('[服务器日志] === 获取房间信息开始 ===');
      console.log('[服务器日志] 收到 get-room-info 事件:');
      console.log('[服务器日志]   - 房间ID:', data.roomId);
      console.log('[服务器日志]   - 请求者ID:', socket.id);
      
      const room = gameRooms.get(data.roomId);
      
      if (!room) {
        console.log('[服务器日志] ❌ 房间不存在');
        socket.emit('error', { message: '房间不存在' });
        console.log('[服务器日志] === 获取房间信息结束 ===');
        return;
      }

      // 构建房间信息
      const roomInfo = {
        roomId: room.roomId,
        playerCount: 1, // 玩家数量固定为1
        spectatorCount: room.spectators.size,
        difficulty: room.difficulty,
        invitePlayMode: room.invitePlayMode,
        gameState: 'playing' // 默认游戏状态为进行中
      };

      console.log('[服务器日志] ✅ 发送房间信息:');
      console.log('[服务器日志]   - 同玩模式:', roomInfo.invitePlayMode ? '开启' : '关闭');
      console.log('[服务器日志]   - 旁观者数量:', roomInfo.spectatorCount);
      
      socket.emit('room-info', roomInfo);
      console.log('[服务器日志] === 获取房间信息完成 ===');
    });

    // 玩家更新游戏状态
    socket.on('update-game', (data: { roomId: string; board: Cell[][] }) => {
      const room = gameRooms.get(data.roomId);
      
      if (!room || room.playerId !== socket.id) {
        return;
      }

      room.board = data.board;
      
      // 广播给该房间的所有旁观者
      socket.to(data.roomId).emit('game-state', {
        board: room.board,
        difficulty: room.difficulty,
        highlightedCells: Array.from(room.highlightedCells)
      });

      // 清除闪烁的格子
      if (room.highlightedCells.size > 0) {
        setTimeout(() => {
          room.highlightedCells.clear();
        }, 100);
      }
    });

    // 旁观者清除所有高亮
    socket.on('clear-all-highlights', (data: { roomId: string }) => {
      const room = gameRooms.get(data.roomId);
      
      if (!room || !room.spectators.has(socket.id)) {
        return;
      }

      // 清除所有高亮格子
      room.highlightedCells.clear();
      
      // 通知玩家清除所有高亮
      io.to(room.playerId).emit('clear-all-highlights');
      
      // 通知所有旁观者清除所有高亮
      io.to(data.roomId).emit('clear-all-highlights');

      console.log(`旁观者清除所有高亮: 房间 ${data.roomId}`);
    });

    // 旁观者点击格子
    socket.on('spectator-click', (data: { roomId: string; row: number; col: number }) => {
      const room = gameRooms.get(data.roomId);
      
      if (!room || !room.spectators.has(socket.id)) {
        return;
      }

      const cellKey = `${data.row},${data.col}`;
      room.highlightedCells.add(cellKey);

      console.log(`旁观者点击: 房间 ${data.roomId}, 格子 (${data.row}, ${data.col})`);
      
      // 通知玩家该格子被旁观者点击
      io.to(room.playerId).emit('spectator-suggest', {
        row: data.row,
        col: data.col
      });

      // 3秒后移除闪烁
      setTimeout(() => {
        room.highlightedCells.delete(cellKey);
        io.to(data.roomId).emit('clear-highlight', { row: data.row, col: data.col });
      }, 3000);
    });

    // 旁观者操作格子（同玩模式）
    socket.on('spectator-action', (data: { roomId: string; action: 'reveal' | 'flag' | 'chord'; row: number; col: number }) => {
      console.log('[服务器日志] === 旁观者操作开始 ===');
      console.log('[服务器日志] 收到 spectator-action 事件:');
      console.log('[服务器日志]   - 房间ID:', data.roomId);
      console.log('[服务器日志]   - 动作类型:', data.action);
      console.log('[服务器日志]   - 格子坐标:', `(${data.row}, ${data.col})`);
      console.log('[服务器日志]   - 旁观者ID:', socket.id);
      
      const room = gameRooms.get(data.roomId);
      
      if (!room) {
        console.log('[服务器日志] ❌ 房间不存在，操作失败');
        console.log('[服务器日志] 当前存在的房间:', Array.from(gameRooms.keys()));
        return;
      }
      
      console.log('[服务器日志] 房间信息:');
      console.log('[服务器日志]   - 玩家ID:', room.playerId);
      console.log('[服务器日志]   - 旁观者数量:', room.spectators.size);
      console.log('[服务器日志]   - 同玩模式:', room.invitePlayMode);
      console.log('[服务器日志]   - 当前旁观者:', Array.from(room.spectators));
      
      if (!room.spectators.has(socket.id)) {
        console.log('[服务器日志] ❌ 旁观者不在房间中，操作失败');
        return;
      }
      
      if (!room.invitePlayMode) {
        console.log('[服务器日志] ❌ 房间未开启同玩模式，操作失败');
        return;
      }

      console.log(`[服务器日志] ✅ 旁观者操作有效: 房间 ${data.roomId}, 动作: ${data.action}, 格子 (${data.row}, ${data.col})`);
      
      // 转发操作给玩家
      console.log('[服务器日志] 转发操作给玩家:', room.playerId);
      io.to(room.playerId).emit('spectator-action', {
        action: data.action,
        row: data.row,
        col: data.col
      });
      console.log('[服务器日志] === 旁观者操作完成 ===');
    });

    // 玩家更新难度
    socket.on('update-difficulty', (data: { roomId: string; difficulty: string; config?: any }) => {
      const room = gameRooms.get(data.roomId);
      
      if (!room || room.playerId !== socket.id) {
        return;
      }

      console.log(`玩家更新难度: 房间 ${data.roomId}, 从 ${room.difficulty} 变更为 ${data.difficulty}`);
      console.log('配置信息:', data.config);
      room.difficulty = data.difficulty;
      
      // 广播难度更新给房间内所有旁观者
      io.to(data.roomId).emit('difficulty-updated', { 
        difficulty: data.difficulty,
        config: data.config // 传递配置信息给旁观者
      });
    });

    // 玩家切换同玩模式
    socket.on('toggle-invite-play-mode', (data: { roomId: string; invitePlayMode: boolean }) => {
      console.log('[服务器日志] === 切换同玩模式开始 ===');
      console.log('[服务器日志] 收到 toggle-invite-play-mode 事件:');
      console.log('[服务器日志]   - 房间ID:', data.roomId);
      console.log('[服务器日志]   - 同玩模式:', data.invitePlayMode ? '开启' : '关闭');
      console.log('[服务器日志]   - 玩家ID:', socket.id);
      
      const room = gameRooms.get(data.roomId);
      
      if (!room || room.playerId !== socket.id) {
        console.log('[服务器日志] ❌ 房间不存在或玩家不匹配，操作失败');
        console.log('[服务器日志] === 切换同玩模式结束 ===');
        return;
      }

      // 更新房间的同玩模式状态
      room.invitePlayMode = data.invitePlayMode;
      
      console.log(`[服务器日志] ✅ 同玩模式已更新: ${data.invitePlayMode ? '开启' : '关闭'}`);
      
      // 广播同玩模式更新给房间内所有旁观者
      console.log('[服务器日志] 广播同玩模式更新给旁观者');
      io.to(data.roomId).emit('invite-play-mode-updated', { 
        invitePlayMode: data.invitePlayMode
      });
      
      console.log('[服务器日志] === 切换同玩模式完成 ===');
    });

    // 断开连接
    socket.on('disconnect', () => {
      console.log('用户断开连接:', socket.id);
      
      // 清理房间数据
      gameRooms.forEach((room, roomId) => {
        if (room.playerId === socket.id) {
          // 玩家离开，关闭房间
          io.to(roomId).emit('room-closed');
          gameRooms.delete(roomId);
          console.log(`房间关闭: ${roomId}`);
        } else if (room.spectators.has(socket.id)) {
          // 旁观者离开
          room.spectators.delete(socket.id);
        }
      });
    });
  });

  return io;
}

// 生成唯一房间ID
function generateRoomId(): string {
  return Math.random().toString(36).substring(2, 10).toUpperCase();
}
