package com.group.robot.handler;

import java.util.Map;
import java.util.UUID;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

import com.group.Protocol;
import com.group.robot.info.RobotInfo;
import com.group.robot.RobotManager;
import com.taurus.core.entity.TObject;
import com.taurus.core.plugin.redis.Redis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import taurus.client.SocketCode;
import taurus.client.TaurusClient;
import taurus.client.Message;
import com.taurus.core.entity.ITObject;
import com.taurus.core.events.Event;
import com.taurus.core.events.IEventListener;
import redis.clients.jedis.Jedis;

/**
 * 机器人连接处理器 - 将机器人连接到游戏服务器并准备
 */
public class RobotConnectionHandler {
    private static volatile RobotConnectionHandler instance;
    private static final Logger log = LoggerFactory.getLogger(RobotConnectionHandler.class);
    
    //机器人ID到客户端连接的映射
    private final Map<Integer, TaurusClient> robotClients = new ConcurrentHashMap<>();

    //机器人ID到连接ID的映射 用于标识每个机器人连接的唯一性
    private final Map<Integer, String> robotConnectionIds = new ConcurrentHashMap<>();
    
    //机器人连接锁，防止重复连接
    private final Map<Integer, Object> robotConnectionLocks = new ConcurrentHashMap<>();

    //机器人管理器引用
    private final RobotManager robotManager;

    private RobotConnectionHandler() {
        this.robotManager = RobotManager.getRobotManager();
    }
    
    public static RobotConnectionHandler getInstance() {
        if (instance == null) {
            synchronized (RobotConnectionHandler.class) {
                if (instance == null) {
                    instance = new RobotConnectionHandler();
                }
            }
        }
        return instance;
    }
    
    /**
     * 连接机器人到游戏服务器
     */
    public void connectRobot(RobotInfo robot) {
        //玩法leftover_robot大于0连接机器人
        if (!robotManager.shouldConnectRobot(robot)) {
            return;
        }
        
        //机器人锁 防止重复连接
        Object lock = robotConnectionLocks.computeIfAbsent(robot.getRobotId(), k -> new Object());
        synchronized (lock) {
            //再次检查是否已经存在有效连接
            TaurusClient existingClient = robotClients.get(robot.getRobotId());
            if (existingClient != null && existingClient.isConnected()) {
                log.debug("机器人 {} 已存在有效连接，跳过重复连接", robot.getRobotId());
                robot.setConnected(true);
                return;
            }
            
            //异步执行连接逻辑
            CompletableFuture.runAsync(() -> {
                try {
                    //连接前再次检查leftover_robot数量 防止并发
                    if (!robotManager.shouldConnectRobot(robot)) {
                        return;
                    }
                    
                    log.info("开始连接机器人 {} 到游戏服务器，玩法ID: {}", robot.getRobotId(), robot.getWanfaId());
                    //TCP客户端连接
                    String serverAddress = getGameServerAddress(robot.getWanfaId());
                    TaurusClient client = new TaurusClient(serverAddress, "game", TaurusClient.ConnectionProtocol.Tcp);
                    client.connect();

                    //发送初始化协议
                    sendInitProtocol(client, robot);

                    //设置事件监听器
                    setTcpEventListeners(client, robot);

                    //唯一连接connecId
                    String connecId = robot.getRobotId() + "_" +UUID.randomUUID().toString().replace("-", "").substring(0, 16);
                    
                    //清理存在的旧连接
                    TaurusClient oldClient = robotClients.remove(robot.getRobotId());
                    if (oldClient != null && oldClient.isConnected()) {
                        oldClient.killConnection();
                    }

                    //保存客户端连接
                    robotClients.put(robot.getRobotId(), client);
                    //保存connecId
                    robotConnectionIds.put(robot.getRobotId(), connecId);

                    //设置机器人连接状态
                    robot.setConnected(true);
                    System.out.println("机器人连接游戏服务器, client状态 :" + client.isConnected() + "机器人 :" + connecId);
                } catch (Exception e) {
                    System.out.println("连接机器人到游戏服务器时发生异常: " + robot.getRobotId());
                    robotClients.remove(robot.getRobotId());
                    robotConnectionIds.remove(robot.getRobotId());
                    robot.setConnected(false);
                    disconnectRobot(robot.getRobotId());
                } finally {
                    if (!robotClients.containsKey(robot.getRobotId())) {
                        robotConnectionLocks.remove(robot.getRobotId());
                    }
                }
            });
        }
    }

    /**
     * 设置初始化阶段的事件监听器
     */
    private void setTcpEventListeners(TaurusClient client, RobotInfo robot) {
        //添加连接状态监听器
        client.addEventListener(TaurusClient.NetClientEvent.Connect, new IEventListener() {
            @Override
            public void handleEvent(Event event) {
                SocketCode code = (SocketCode) event.getParameter("code");
                if (code == SocketCode.Connect) {
                    log.info("机器人 {} 连接游戏服务器成功", robot.getRobotId());
                    robot.setConnected(true);
                } else {
                    log.warn("机器人 {} 连接游戏服务器失败: {}", robot.getRobotId(), code);
                    robot.setConnected(false);
                }
            }
        });

        client.addEventListener(TaurusClient.NetClientEvent.OnEvent, new IEventListener() {
            @Override
            public void handleEvent(Event event) {
                try {
                    //获取游戏服务器消息
                    Message message = (Message) event.getParameter("msg");
                    if (message == null) {
                        return;
                    }
                    //协议号
                    String command = message.command;
                    //协议参数
                    Object param = message.param;
                    
                    log.debug("机器人 {} 收到游戏服务器协议: {}, 参数: {}", robot.getRobotId(), command, param);

                } catch (Exception e) {
                    log.error("处理游戏服务器协议事件时发生异常", e);
                }
            }
        });
    }

    /**
     * 根据游戏ID获取服务器地址
     */
    private String getGameServerAddress(int wanfaId) {
        //根据玩法ID返回对应的服务器地址
        switch (wanfaId) {
            case 10: //长沙麻将
                return "192.168.0.32:8701";
            case 22: //红中麻将
                return "8.138.242.190:6421";
            case 66: //跑得快
                return "8.138.242.190:6841";
            default:
                log.warn("未知的玩法ID: {}, 使用默认服务器地址", wanfaId);
                return "127.0.0.1:6311"; //默认地址
        }
    }
    
    /**
     * 断开机器人连接
     */
    public void disconnectRobot(int robotId) {
        try {
            log.info("清理机器人 {} 的连接资源", robotId);
            Object lock = robotConnectionLocks.computeIfAbsent(robotId, k -> new Object());
            synchronized (lock) {
                //移除机器人TCP客户端连接
                TaurusClient client = robotClients.remove(robotId);
                if (client != null) {
                    client.killConnection();
                    log.debug("已清理机器人 {} 的客户端连接", robotId);
                }
                //移除连接ID
                robotConnectionIds.remove(robotId);
                
                //清理锁对象
                robotConnectionLocks.remove(robotId);
            }
            
            //从RobotManager中获取机器人信息并断开连接
            RobotInfo robot = robotManager.getConnectedRobot(robotId);
            if (robot != null) {
                robotManager.safeDisconnectRobot(robotId, robot.getGroupId(), robot.getWanfaId(), robot.getRoomId());
            }
        } catch (Exception e) {
            log.error("断开机器人连接时发生异常: " + robotId, e);
        }
    }

    /**
     * 发送初始化协议
     */
    private void sendInitProtocol(TaurusClient client, RobotInfo robot) {
        if (client == null || !client.isConnected()) {
            log.warn("机器人 {} 没有有效的TCP连接，无法发送初始化协议", robot.getRobotId());
            return;
        }

        ITObject param = new TObject();
        param.putString("type", "robot_mj_cs");
        param.putString("client", "robot_mgr");
        param.putString("session", robot.getSession() + "," + robot.getToken());
        client.send("init_connection", param, response -> {
            if (response != null && response.returnCode == 0) {
                log.info("机器人 {} 初始化协议发送成功", robot.getRobotId());
            }
        });
    }

    /**
     * 异步发送准备消息给指定机器人
     */
    public CompletableFuture<Boolean> sendReadyMessage(RobotInfo robot, CompletableFuture<Boolean> future) {
        TaurusClient client = robotClients.get(robot.getRobotId());
        if (client == null) {
            future.complete(false);
            return future;
        }

        ITObject readyParam = new TObject();
        readyParam.putInt("groupId", robot.getGroupId());
        readyParam.putString("roomId", robot.getRoomId());

        readyParam.putString("session", robot.getSession() + "," + robot.getToken());
        readyParam.putString("robotId", String.valueOf(robot.getRobotId()));
        readyParam.putString("connecId", robotConnectionIds.get(robot.getRobotId()));

        //超时
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if (!future.isDone()) {
                    future.completeExceptionally(new RuntimeException("加入房间超时"));
                }
            }
        }, 10000);

        client.send("1002", readyParam, response -> {
            boolean success = response != null && response.returnCode == 0;
            if (!future.isDone()) {
                future.complete(success);
            }
            timer.cancel();
        });

        return future;
    }

    /**
     * 异步发送准备消息给指定机器人
     */
    public CompletableFuture<Boolean> sendReadyMessage(RobotInfo robot) {
        CompletableFuture<Boolean> future = new CompletableFuture<>();
        
        TaurusClient client = robotClients.get(robot.getRobotId());
        if (client == null) {
            future.complete(false);
            return future;
        }

        ITObject readyParam = new TObject();
        readyParam.putString("session", robot.getSession() + "," + robot.getToken());
        readyParam.putString("robotId", String.valueOf(robot.getRobotId()));
        readyParam.putString("connecId", robotConnectionIds.get(robot.getRobotId()));
        
        //超时机制
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if (!future.isDone()) {
                    future.completeExceptionally(new RuntimeException("Ready message timeout"));
                }
            }
        }, 10000);
        
        client.send("1003", readyParam, response -> {
            boolean success = response != null && response.returnCode == 0;
            if (!future.isDone()) {
                future.complete(success);
            }
            timer.cancel();
        });
        
        return future;
    }

    /**
     * 回调接口
     */
    public interface RoomCreatedCallback {
        void onRoomCreated(RobotInfo robot);
    }
    
    private RoomCreatedCallback roomCreatedCallback;
    
    public void setRoomCreatedCallback(RoomCreatedCallback callback) {
        this.roomCreatedCallback = callback;
    }

    /**
     * 发送创建房间请求
     */
    public void sendCreateRoom(RobotInfo robot, int groupId, int wanfaId) {
        TaurusClient client = robotClients.get(robot.getRobotId());
        //todo !client.isConnected()
        if (client == null || !client.isConnected()) {
            connectRobot(robot);
            return;
        }

        ITObject param = new TObject();
        param.putInt("groupId", groupId);
        param.putInt("wanfaId", wanfaId);
        param.putInt("robotId", robot.getRobotId());
        param.putString("session", robot.getSession() + "," + robot.getToken());
        client.send(Protocol.CREATE_ROOM_FOR_ROBOT, param, response -> {
            if (response != null && response.returnCode == 0) {
                ITObject responseData = response.messageData.param;
                String roomId = responseData.getString("roomKey");
                log.info("机器人 {} 成功创建房间 {}", robot.getRobotId(), roomId);
                if (roomCreatedCallback != null) {
                    robot.setRoomId(roomId);
                    robot.setGroupId(groupId);
                    robot.setWanfaId(wanfaId);
                    roomCreatedCallback.onRoomCreated(robot);
                }
            }
        });
    }
}