package robot.mj;

import com.taurus.core.entity.ITArray;
import com.taurus.core.entity.ITObject;
import com.taurus.core.entity.TArray;
import com.taurus.core.entity.TObject;
import com.taurus.core.events.Event;
import com.taurus.core.events.IEventListener;
import com.taurus.core.plugin.redis.Redis;
import com.taurus.core.util.ICallback;
import com.taurus.core.util.StringUtil;
import org.apache.log4j.Logger;
import robot.mj.business.AccountBusiness;
import robot.mj.handler.HuNanHongZhong;
import robot.mj.info.RobotUser;
import taurus.client.Message;
import taurus.client.MessageResponse;
import taurus.client.TaurusClient;
import taurus.client.SocketCode;
import redis.clients.jedis.Jedis;

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

import static robot.mj.EXGameController.robotRoomMapping;
import static robot.mj.thread.ThreadPoolConfig.scheduleDelay;

/**
 * 机器人连接管理器 - 管理与游戏服务器的连接
 */
public class RobotConnectionManager {

    private static final Map<String, HuNanHongZhong> huNanHongZhongInstances = new ConcurrentHashMap<>();
    private static final Logger log = Logger.getLogger(RobotConnectionManager.class);
    private final EXGameController exGameController;

    private final String host= Config.GAME_SERVER_HOST;
    private final int port= Integer.parseInt(Config.GAME_SERVER_PORT);


    public RobotConnectionManager() {
        exGameController = new EXGameController();
    }

    /**
     * 获取红中麻将处理器实例
     */
    private HuNanHongZhong getHuNanHongZhongInstance(String connecId) {
        HuNanHongZhong existingInstance = huNanHongZhongInstances.get(connecId);
        if (existingInstance != null) {
            return existingInstance;
        }

        HuNanHongZhong newInstance = new HuNanHongZhong();
        
        //从Redis恢复状态
        boolean restored = newInstance.restoreFromRedis(connecId);
        if (restored) {
            System.out.println("从Redis恢复HuNanHongZhong实例: " + connecId);
        } else {
            System.out.println("创建新的HuNanHongZhong实例: " + connecId);
        }
        
        huNanHongZhongInstances.put(connecId, newInstance);
        System.out.println("当前HuNanHongZhong实例总数: " + huNanHongZhongInstances.size());
        return newInstance;
    }

    /**
     * 设置会话和令牌
     */
    public void setSessionAndToken(String session, String token, String connecId) {
        HuNanHongZhong instance = getHuNanHongZhongInstance(connecId);
        instance.session = session;
        instance.token = token;
    }

    /**
     * 连接到红中麻将游戏服务器
     */
    public TaurusClient connectToGameServer(String connecId) {
        try {
            //创建Taurus客户端
            TaurusClient client = new TaurusClient(host + ":" + port, "game", TaurusClient.ConnectionProtocol.Tcp);

            //设置事件监听器
            setupEventListeners(client, connecId);

            client.connect();

            return client;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 断开与游戏服务器的连接（主动断开）
     */
    public void disconnectFromGameServer(String connecId) {
        System.out.println("开始主动断开连接: {"+connecId+"}");
        RobotUser robotUser = robotRoomMapping.remove(connecId);

        //清理连接数据
        if (connecId != null) {
            HuNanHongZhong.removeFromRedis(connecId);
            
            HuNanHongZhong instance = huNanHongZhongInstances.get(connecId);
            if (instance != null) {
                instance.getHongZhongCardInhand().clear();
                instance.getChuGuoCardInhand().clear();
                System.out.println("清空HuNanHongZhong集合数据: " + connecId);
            }
            
            huNanHongZhongInstances.remove(connecId);
        }

        if (robotUser != null) {
            TaurusClient client = robotUser.getClient();
            if (client != null) {
                try {
                    if (client.isConnected()) {
                        client.killConnection();
                    }
                    System.out.println("客户端主动断开连接完成: {"+connecId+"}");
                } catch (Exception e) {
                    System.out.println("断开客户端连接时发生异常: " + connecId + ", 错误: " + e.getMessage());
                }
            } else {
                System.out.println("客户端连接不存在: {"+connecId+"}");
            }
        }
    }

    /**
     * 设置事件监听器
     */
    public void setupEventListeners(TaurusClient client, String connecId) {
        //添加消息事件监听器
        IEventListener messageListener = new IEventListener() {
            @Override
            public void handleEvent(Event event) {
                //获取 msg
                Message message = (Message) event.getParameter("msg");

                ITObject param = message.param;
                //回调协议号
                String command = message.command;
                System.out.println("csmj OnEvent msg： " + command);

                //根据玩法ID处理不同的回调
                if (StringUtil.isNotEmpty(command)) {
                    //直接处理协议
                    handleProtocol(command, message, client, connecId);
                }
            }
        };

        //添加连接状态监听器
        IEventListener connectListener = new IEventListener() {
            @Override
            public void handleEvent(Event event) {
                Message message = (Message) event.getParameter("msg");
                SocketCode code = (SocketCode) event.getParameter("code");

            }
        };

        //注册事件监听器
        client.addEventListener(TaurusClient.NetClientEvent.OnEvent, messageListener);
        client.addEventListener(TaurusClient.NetClientEvent.Connect, connectListener);
    }


    /**
     * 机器人断线重连
     */
    public void reconnectToGameServer(MessageResponse response, RobotUser robotUser, TaurusClient client) {
        String connecId = robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId();
        if(client.isConnected()){
            try {
                ITObject obj = response.messageData.param.getTObject("tableInfo");
                ITObject reloadInfo = response.messageData.param.getTObject("reloadInfo");
                if (obj != null) {
                    //处理 seat
                    //获取机器人的seat
                    ITArray playerData = obj.getTArray("playerData");
                    for (int i = 0; i < playerData.size(); i++) {
                        ITObject tms = playerData.getTObject(i);
                        Integer tmuserid = tms.getInt("aid");
                        if (tmuserid == Integer.parseInt(robotUser.getRobotId())) {
                            Integer seat = tms.getInt("seat");
                            robotUser.setSeat(seat);
                        }
                    }
                    System.out.println("playerData:" + playerData);

                    System.out.println("obj:" + obj);
                    System.out.println("reloadInfo:" + reloadInfo);
                    if (reloadInfo != null) {
                        //重连回来的
                        int curren_outcard_seat = reloadInfo.getInt("curren_outcard_seat");
                        if (curren_outcard_seat == robotUser.getSeat()) {
                            //同步手牌
                            ITArray hand_card = reloadInfo.getTArray("hand_card");
                            ITArray info_list = reloadInfo.getTArray("info_list");

                            List<Integer> hcard = new ArrayList<>();
                            if (hand_card != null) {
                                for (int i = 0; i < hand_card.size(); i++) {
                                    hcard.add(hand_card.getInt(i));
                                }
                            }
                            ITArray outcard_list = new TArray();
                            if (info_list != null) {
                                for (int i = 0; i < info_list.size(); i++) {
                                    ITObject tms = info_list.getTObject(i);
                                    Integer playerid = tms.getInt("playerid");
                                    if (playerid == Integer.parseInt(robotUser.getRobotId())) {
                                        outcard_list = tms.getTArray("outcard_list");
                                    }
                                }
                            }

                            System.out.println("hcard>0" + hcard);
                            if (hcard.size() > 0) {
                                //同步手牌
                                HuNanHongZhong currentInstance = getHuNanHongZhongInstance(connecId);

                                //同步逻辑比较手牌数量
                                List<Integer> currentHand = currentInstance.getHongZhongCardInhand();
                                if (currentHand.isEmpty() || hcard.size() > currentHand.size()) {
                                    //手牌集合为空 或者 玩家出牌了
                                    currentInstance.updateHandCard(hcard);
                                    System.out.println("断线重连：同步手牌数据，服务器手牌:" + hcard);
                                } else {
                                    System.out.println("断线重连：使用Redis恢复的手牌数据，数量:" + currentHand.size());
                                }

                                if (outcard_list.size() > 0) {
                                    List<Integer> outcards = new ArrayList<>();
                                    for (int i = 0; i < outcard_list.size(); i++) {
                                        outcards.add(outcard_list.getInt(i));
                                    }

                                    //检查出牌记录是否需要同步
                                    List<Integer> currentOutCards = currentInstance.getChuGuoCardInhand();
                                    if (currentOutCards.isEmpty() || outcards.size() > currentOutCards.size()) {
                                        currentInstance.updateOutCard(outcards);
                                        System.out.println("断线重连：同步出牌数据，服务器出牌:" + outcards);
                                    } else {
                                        System.out.println("断线重连：使用Redis恢复的出牌数据，数量:" + currentOutCards.size());
                                    }
                                }

                                sleepTime(2000);
                                currentInstance.outCard(client);
                            } else {
                                System.err.println("警告：重连时未获取到手牌数据");
                            }
                        }
                    }
                }
            }finally {

            }
        }else {
            renconnect(robotUser);
        }
    }

    /**
     * 处理接收到的游戏协议
     */
    private void handleProtocol(String command, Message message, TaurusClient client, String connecId) {
        RobotUser robotUser = robotRoomMapping.get(connecId);
        int robotId = Integer.parseInt(robotUser.getRobotId());
        ITObject param = message.param;
        HuNanHongZhong huNanHongZhong = getHuNanHongZhongInstance(connecId);
        Jedis jedis0 = Redis.use().getJedis();
        Jedis jedis2 = Redis.use("group1_db2").getJedis();
        try {
            //红中麻将 机器人处理事件
            //出牌广播
            if ("812".equalsIgnoreCase(command)) {
                huNanHongZhong.drawCard(command, message);
                //处理完协议后保存到Redis
                HuNanHongZhong currentInstance = huNanHongZhongInstances.get(connecId);
                currentInstance.saveToRedis(connecId);
            }
            //初始化手牌
            else if ("811".equalsIgnoreCase(command)) {
                huNanHongZhong.cardInHead(command, message, client);
                //处理完协议后保存到Redis
                HuNanHongZhong currentInstance = huNanHongZhongInstances.get(connecId);
                currentInstance.saveToRedis(connecId);
            }
            //摸牌
            else if ("819".equalsIgnoreCase(command)) {
                huNanHongZhong.getCard(command, message);
                //处理完协议后保存到Redis
                HuNanHongZhong currentInstance = huNanHongZhongInstances.get(connecId);
                currentInstance.saveToRedis(connecId);
            }
            //出牌，牌权
            else if ("813".equalsIgnoreCase(command)) {
                huNanHongZhong.outCard(client);
                //处理完协议后保存到Redis
                HuNanHongZhong currentInstance = huNanHongZhongInstances.get(connecId);
                currentInstance.saveToRedis(connecId);
            }
            //结算
            else if ("817".equalsIgnoreCase(command)) {
                huNanHongZhong.getHongZhongCardInhand().clear();
                huNanHongZhong.getChuGuoCardInhand().clear();
                System.out.println("红中结算");
                Integer type = param.getInt("type");
                if (type == 1 || type == 2) {  //为1 为大结算 为2为解散,都需要恢复数据
                    //更新机器人剩余数量
                    updateLeftoverRobot(Integer.parseInt(robotUser.getRobotId()));
                }
                ITObject params = TObject.newInstance();
                params.putString("session", client.getSession());
                client.send("1003", params, new ICallback<MessageResponse>() {
                    @Override
                    public void action(MessageResponse messageResponse) {

                    }
                });
            }
            //杠碰胡通知协议
            else if ("814".equalsIgnoreCase(command)) {
                huNanHongZhong.actionCard(param, client);
                //处理完协议后保存到Redis
                HuNanHongZhong currentInstance = huNanHongZhongInstances.get(connecId);
                currentInstance.saveToRedis(connecId);
            } else if ("820".equalsIgnoreCase(command)) {
                HuNanHongZhong.changePlayer(command, message);
                //处理完协议后保存到Redis
                HuNanHongZhong currentInstance = huNanHongZhongInstances.get(connecId);
                currentInstance.saveToRedis(connecId);
            }
            //服务器通知客户端有玩家执行了操作
            else if ("815".equalsIgnoreCase(command)) {
                huNanHongZhong.shanchuchuguopai(param);
                //处理完协议后保存到Redis
                HuNanHongZhong currentInstance = huNanHongZhongInstances.get(connecId);
                currentInstance.saveToRedis(connecId);
            }
            //玩家加入房间
            else if ("2001".equalsIgnoreCase(command)) {
                scheduleDelay(() -> {
                    try {
                        String roomKey = String.valueOf(robotUser.getCurrentRoomId());

                        //查询该房间的玩家信息
                        String playersStr = jedis0.hget("room:"+roomKey, "players");
                        if (!playersStr.equals("[]")) {
                            String players = playersStr.substring(1, playersStr.length() - 1);
                            String[] playerIds = players.split(",");

                            //判断只有当前机器人一个玩家
                            if (playerIds.length == 1) {
                                int playerId = Integer.parseInt(playerIds[0].trim());
                                if (playerId == robotId) {

                                    //发送退出房间协议
                                    ITObject params = TObject.newInstance();
                                    client.send("1005", params, response -> {
                                        EXGameController.removeRobotRoomInfo(String.valueOf(robotId));
                                        //更新机器人剩余数量
                                        updateLeftoverRobot(robotId);
                                        disconnectFromGameServer(connecId);
                                        System.out.println("2002发送退出房间协议1005，robotId: {"+robotId+"}");
                                    });
                                }
                            }
                        }
                    } catch (Exception e) {
                        log.error("处理玩家加入房间检查时发生异常", e);
                    }
                }, 6, TimeUnit.SECONDS);
                System.out.println("玩家{"+ robotUser.getCurrentRoomId()+"}加入房间:"+ param);
            }
            //玩家退出房间也要检查
            else if ("2002".equalsIgnoreCase(command)) {
                //直接使用定时任务替代Thread.sleep，避免嵌套异步调用
                scheduleDelay(() -> {
                    Jedis jedis = Redis.use().getJedis();
                    try {
                        String roomKey = String.valueOf(robotUser.getCurrentRoomId());

                        //查询该房间的玩家信息
                        String playersStr = jedis.hget("room:"+roomKey, "players");
                        if (!playersStr.equals("[]")) {
                            String players = playersStr.substring(1, playersStr.length() - 1);
                            String[] playerIds = players.split(",");

                            //判断只有当前机器人一个玩家
                            if (playerIds.length == 1) {
                                int playerId = Integer.parseInt(playerIds[0].trim());
                                if (playerId == robotId) {

                                    //发送退出房间协议
                                    ITObject params = TObject.newInstance();
                                    client.send("1005", params, response -> {
                                        EXGameController.removeRobotRoomInfo(String.valueOf(robotId));
                                        //更新机器人剩余数量
                                        updateLeftoverRobot(robotId);
                                        disconnectFromGameServer(connecId);
                                        System.out.println("2002发送退出房间协议1005，robotId: {"+robotId+"}");
                                    });
                                }
                            }
                        }
                    } catch (Exception e) {
                        log.error("处理玩家退出房间检查时发生异常", e);
                    } finally {
                        if (jedis != null) {
                            jedis.close();
                        }
                    }
                }, 6, TimeUnit.SECONDS);
            }
            //玩家解散房间
            else if ("2005".equalsIgnoreCase(command)) {
                EXGameController.removeRobotRoomInfo(String.valueOf(robotId));
                //更新机器人剩余数量
                updateLeftoverRobot(robotId);
                disconnectFromGameServer(connecId);
                System.out.println("2005玩家发送解散房间协议，robotId: {"+robotId+"}");
            }
            //解散房间时候恢复机器人账号可以使用
            else if ("2008".equalsIgnoreCase(command)) {
                updateLeftoverRobot(Integer.parseInt(robotUser.getRobotId()));
                disconnectFromGameServer(connecId);
            }
            else if ("2009".equalsIgnoreCase(command)) {
                scheduleDelay(() -> {
                    Jedis localJedis = Redis.use().getJedis();
                    try {
                        Integer paramRobotId = param.getInt("aid");
                        if (robotUser != null) {
                            String roomKey = String.valueOf(robotUser.getCurrentRoomId());

                            //查询该房间的玩家信息
                            String playersStr = jedis0.hget(roomKey, "players");
                            if (!playersStr.equals("[]")) {
                                String players = playersStr.substring(1, playersStr.length() - 1);
                                String[] playerIds = players.split(",");

                                //判断只有当前机器人一个玩家
                                if (playerIds.length == 1) {
                                    int playerId = Integer.parseInt(playerIds[0].trim());
                                    if (playerId == paramRobotId) {

                                        String gpid = jedis0.hget(roomKey, "gpid");
                                        String gpId = jedis0.hget(roomKey, "group");

                                        //发送退出房间协议
                                        ITObject params = TObject.newInstance();
                                        client.send("1005", params, response -> {
                                            EXGameController.removeRobotRoomInfo(String.valueOf(paramRobotId));
                                            //断开连接
                                            disconnectFromGameServer(connecId);
                                            //更新机器人剩余数量
                                            updateLeftoverRobot(paramRobotId);
                                            System.out.println("2009发送退出房间协议1005，robotId: {"+paramRobotId+"}");
                                        });
                                    }
                                }
                            }
                        }
                    } catch (Exception e) {
                        log.error("处理机器人房间映射检查时发生异常", e);
                    } finally {
                        if (localJedis != null) {
                            localJedis.close();
                        }
                    }
                }, 6, TimeUnit.SECONDS);
            }
        } catch (Exception e) {
            log.error("处理接收到的游戏协议异常");
        } finally {
            jedis0.close();
            jedis2.close();
        }
    }

    /**
     * 增加leftover_robot数量 机器人退出房间
     */
    private void updateLeftoverRobot(int robotId) {
        Jedis jedis2 = Redis.use("group1_db2").getJedis();
        try {

            jedis2.hset("gallrobot", String.valueOf(robotId), "0");

            jedis2.hset("{grobot}:" + robotId, "start", "0");

            System.out.println("机器人 {"+robotId+"} 退出房间，修改gallrobot为0");
        } finally {
            jedis2.close();
        }
    }

    /**
     * 机器人登录
     */
    public void login(RobotUser robotUser){
        System.out.println("login:"+robotUser.getRobotId());
        ITObject object = null;
        AccountBusiness accountBusiness = null;
        accountBusiness = new AccountBusiness();
        try {
            //先快速登录
            object = accountBusiness.fastLogin(Integer.parseInt(robotUser.getRobotId()));
            System.out.println("object:"+object);
            if(object==null){
                object = accountBusiness.idPasswordLogin(Integer.parseInt(robotUser.getRobotId()), robotUser.getPassword());
            }
            ITObject finalObject = object;
            CompletableFuture.runAsync(() -> {
                if (finalObject != null) {
                    //判断是否有房间
                    if(finalObject.getTObject("account")!=null){
                        ITObject validate = TObject.newInstance();
                        validate.putString("token", finalObject.getString("token"));
                        robotUser.setToken(finalObject.getString("token"));;
                        robotUser.setLoginsession("{user}:"+robotUser.getRobotId());
                        if (robotUser.getLoginsession() != null) {
                            robotUser.setIsLogin(true);
                        }
                        if(finalObject.getTObject("account").get("roomid")!=null){
                            String roomid = finalObject.getTObject("account").get("roomid").toString();
                            robotUser.setCurrentRoomId(Integer.parseInt(roomid));
                            connectGame(robotUser);

                            robotUser.setConnecId(robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId());
                            System.err.println("重启获取的机器人还有当前房间，准备加入: "+robotUser.getConnecId());
                            exGameController.webGroupJoinRoom(robotUser);
                        }
                    }
                }
            });
        } catch (Exception e) {
            log.error("机器人登录异常");
        }
    }

    public void connectGame(RobotUser robotUser){
        if(robotUser.isLogin){
            if(robotUser.getClient()==null){
                TaurusClient client = new TaurusClient(robotUser.getGameHost()+":"+robotUser.getGamePort(), "hz"+robotUser.getRobotId(), TaurusClient.ConnectionProtocol.Tcp);
                client.setSession(robotUser.getLoginsession());
                client.connect();
                setupEventListeners(client, robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId());
                robotUser.setIsconnect(client.isConnected());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    log.error("连接超时异常");
                }
                robotUser.setClient(client);
                EXGameController.robotRoomMapping.put(robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId(), robotUser);
            }else{
                System.out.println("reconnect");
                System.out.println("client.isConnected()"+robotUser.getClient().isConnected());
                if(robotUser.getClient().isConnected()){
                    robotUser.setIsconnect(true);
                }else{
                    System.out.println("reconnect"+robotUser.getClient().getGameID());
                    TaurusClient client = new TaurusClient(robotUser.getGameHost()+":"+robotUser.getGamePort(), "hz"+robotUser.getRobotId(), TaurusClient.ConnectionProtocol.Tcp);
                    client.setSession(robotUser.getLoginsession());
                    client.connect();
                    robotUser.setIsconnect(client.isConnected());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        log.error("连接超时异常");
                    }
                    robotUser.setClient(client);
                    EXGameController.robotRoomMapping.put(robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId(), robotUser);
                }
            }
        }
    }

    /**
     * 重连
     */
    public void renconnect(RobotUser robotUser){
        TaurusClient client = robotUser.getClient();
        if(client!=null){
            if(client.isConnected()){
                client.connect();
                robotUser.setIsconnect(client.isConnected());
            }
        }
    }

    /**
     * 根据connecId获取游戏服务器连接
     */
    public TaurusClient getGameClient(String connecId) {
        return robotRoomMapping.get(connecId) != null ? robotRoomMapping.get(connecId).getClient() : null;
    }


    public int getTime(){
        return Integer.parseInt((System.currentTimeMillis() + "").substring(0, 10));
    }

    public static void sleepTime(int time) {
        try {
            //添加延迟
            Thread.sleep(time);
        } catch (InterruptedException e) {
            log.error("连接超时异常");
        }
    }

}