package com.zombie.game.server;

import com.zombie.game.ecs.ECSWorld;
import com.zombie.game.ecs.components.*;
import com.zombie.game.model.*;
import com.zombie.game.systems.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Core game service managing game lifecycle and state / 核心游戏服务，管理游戏生命周期和状态
 */
public class GameService {
    // Logger for game events / 游戏事件日志记录器
    private static final Logger logger = LoggerFactory.getLogger(GameService.class);

    // Active game worlds mapped by room ID / 活跃的游戏世界，以房间ID映射
    private final Map<String, ECSWorld> activeGames = new ConcurrentHashMap<>();
    // Game loops mapped by room ID / 游戏循环，以房间ID映射
    private final Map<String, GameLoop> gameLoops = new ConcurrentHashMap<>();
    // Callback for broadcasting game state / 广播游戏状态的回调
    private final GameStateBroadcast broadcaster;

    // Interface for broadcasting game state to clients / 向客户端广播游戏状态的接口
    public interface GameStateBroadcast {
        void broadcast(String roomId, ECSWorld world);
    }

    // Constructor with broadcast callback / 带广播回调的构造函数
    public GameService(GameStateBroadcast broadcaster) {
        this.broadcaster = broadcaster;
    }

    // Start a new game for the given room / 为指定房间启动新游戏
    public Map<String, Map<String, Object>> startGame(Room room) {
        // Load map from system property or default / 从系统属性或默认路径加载地图
        String mapPath = System.getProperty("map.path", "maps/d540209a.json");
        ECSWorld world = new ECSWorld(mapPath);

        // Add systems in order: input -> flow field -> zombie spawn -> zombie movement
        world.addSystem(new PlayerInputSystem());
        world.addSystem(new FlowFieldUpdateSystem());
        world.addSystem(new ZombieSpawnSystem());
        world.addSystem(new ZombieMovementSystem());

        // Spawn players at map spawn points / 在地图出生点生成玩家
        int index = 0;
        List<int[]> spawnPoints = world.getMap().getSpawnPoints();

        for (PlayerInfo playerInfo : room.getPlayers()) {
            int[] sp = spawnPoints.get(index % spawnPoints.size());
            float wx = sp[0] + 0.5f;
            float wy = sp[1] + 0.5f;
            world.createPlayerEntity(playerInfo.getId(), playerInfo.getName(), wx, wy);
            index++;
        }

        // Spawn test zombies at zombie spawn points / 在僵尸出生点生成测试僵尸
        List<int[]> zombieSpawns = world.getMap().getZombieSpawnPoints();
        for (int[] zsp : zombieSpawns) {
            int zombieId = world.createZombieEntity(zsp[0] + 0.5f, zsp[1] + 0.5f);
            logger.info("Initial zombie created: id={} at ({}, {})", zombieId, zsp[0], zsp[1]);
        }

        activeGames.put(room.getId(), world);

        // Build initial data for each player / 为每位玩家构建初始数据
        Map<String, Map<String, Object>> playerInitData = new LinkedHashMap<>();
        for (PlayerInfo playerInfo : room.getPlayers()) {
            Map<String, Object> data = new LinkedHashMap<>();
            data.put("playerId", playerInfo.getId());
            data.put("mapData", serializeMapData(world.getMapData()));

            // Build player list with positions / 构建包含位置的玩家列表
            List<Map<String, Object>> playerList = new ArrayList<>();
            int idx = 0;
            for (PlayerInfo p : room.getPlayers()) {
                Integer entityId = world.getPlayerEntity(p.getId());
                Map<String, Object> pm = new LinkedHashMap<>();
                pm.put("id", p.getId());
                pm.put("name", p.getName());
                if (entityId != null) {
                    Position pos = world.getPositions().get(entityId);
                    if (pos != null) {
                        pm.put("x", pos.getX());
                        pm.put("y", pos.getY());
                    }
                }
                pm.put("index", idx++);
                playerList.add(pm);
            }
            data.put("players", playerList);
            playerInitData.put(playerInfo.getId(), data);
        }

        // Create game loop (not started yet) / 创建游戏循环（尚未启动）
        GameLoop loop = new GameLoop(room.getId(), world, broadcaster);
        gameLoops.put(room.getId(), loop);

        logger.info("Game initialized for room: {}", room.getId());
        return playerInitData;
    }

    // Start the game loop for a room (call after sending game_started) / 启动房间的游戏循环（在发送 game_started 之后调用）
    public void startGameLoop(String roomId) {
        GameLoop loop = gameLoops.get(roomId);
        if (loop != null) {
            loop.start();
        }
    }

    // Stop the game for a room / 停止指定房间的游戏
    public void stopGame(String roomId) {
        GameLoop loop = gameLoops.remove(roomId);
        if (loop != null) {
            loop.stop();
        }
        activeGames.remove(roomId);
        logger.info("Game stopped for room: {}", roomId);
    }

    // Process player input for movement and aiming / 处理玩家输入（移动和瞄准）
    public void processPlayerInput(String roomId, String playerId,
                                   float dx, float dy, float aimX, float aimY, int seq) {
        ECSWorld world = activeGames.get(roomId);
        if (world == null) return;

        synchronized (world.getLock()) {
            Integer entityId = world.getPlayerEntity(playerId);
            if (entityId == null) return;

            // Skip if player is dead / 如果玩家已死亡则跳过
            Health health = world.getHealths().get(entityId);
            if (health == null || !health.isAlive()) return;

            // Apply input to player entity / 将输入应用到玩家实体
            PlayerInput input = world.getPlayerInputs().get(entityId);
            if (input == null) return;

            input.setDx(dx);
            input.setDy(dy);
            input.setAimX(aimX);
            input.setAimY(aimY);
            input.setSeq(seq);
        }
    }

    // Convert 2D int array to nested list for JSON serialization / 将二维整数数组转换为嵌套列表用于JSON序列化
    private List<List<Integer>> serializeMapData(int[][] cells) {
        List<List<Integer>> result = new ArrayList<>();
        for (int[] row : cells) {
            List<Integer> rowList = new ArrayList<>();
            for (int cell : row) {
                rowList.add(cell);
            }
            result.add(rowList);
        }
        return result;
    }
}
