package com.example.demo.module.friend;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.common.GlobalRoot;
import com.example.demo.module.user.Player;
import com.example.demo.table.UserFriend;
import com.example.demo.table.UserFriendRequest;
import com.example.demo.table.user.UserInfo;
import org.apache.catalina.User;
import org.apache.logging.log4j.util.Strings;
import pers.jc.engine.JCEngine;
import pers.jc.network.SocketComponent;
import pers.jc.network.SocketMethod;
import pers.jc.network.SocketResponse;
import pers.jc.sql.SQL;
import pers.jc.util.JCLogger;

import java.util.*;

/**
 * Socket组件-好友
 */
@SocketComponent("friendComp")
public class FriendComp {

    @SocketMethod(async = true)
    public void getMyFriends(Player player, SocketResponse socketResponse) {
        String sql = new SQL(){
            @Override
            public String toString() {
                return "SELECT myID, friendID, avatarID, avatarUrl, nickname, offlineTime FROM user_friend JOIN user_info WHERE myID = " + PARAM(player.userID) + " AND friendID = id";
            }
        }.toString();
        List<JSONObject> friendList = GlobalRoot.db.select(sql);
        JCEngine.gameService.execute(() -> {
            for (JSONObject jo: friendList) {
                int friendID = jo.getInteger("friendID");
                jo.put("online", Player.playerMap.get(friendID) == null ? false : true);
            }
            sortByOnline(friendList);
            socketResponse.send(friendList);
        });
    }

    @SocketMethod(async = true)
    public void deleteMyFriend(Player player, SocketResponse socketResponse, int friendID) {
        UserFriend userFriend = new UserFriend();
        userFriend.setMyID(player.userID);
        userFriend.setFriendID(friendID);
        UserFriend userFriend2 = new UserFriend();
        userFriend2.setMyID(friendID);
        userFriend2.setFriendID(player.userID);
        int res = GlobalRoot.db.delete(userFriend, userFriend2);
        socketResponse.send(res > 0 ? true : false);
    }

    @SocketMethod(async = true)
    public void getFriendRequestList(Player player, SocketResponse socketResponse) {
        String sql = new SQL(){
            @Override
            public String toString() {
                return "SELECT myID, otherID, avatarID, avatarUrl, nickname, offlineTime FROM user_friend_request JOIN user_info WHERE myID = " + PARAM(player.userID) + " AND otherID = id";
            }
        }.toString();
        List<JSONObject> requestList = GlobalRoot.db.select(sql);
        JCEngine.gameService.execute(() -> {
            for (JSONObject jo: requestList) {
                int otherID = jo.getInteger("otherID");
                jo.put("online", Player.playerMap.get(otherID) == null ? false : true);
            }
            sortByOnline(requestList);
            socketResponse.send(requestList);
        });
    }

    /**
     * 请求添加好友
     * @param otherID 目标用户ID
     */
    @SocketMethod(async = true)
    public void requestAddFriend(Player player, int otherID) {
        if (player.userID == otherID) return; //自己不能添加自己

        //已经是好友就不再发送请求
        UserFriend userFriend = GlobalRoot.db.selectOne(UserFriend.class, new SQL(){{
            WHERE("myID = " + PARAM(otherID));
            WHERE("friendID = " + PARAM(player.userID));
        }});
        if (userFriend != null) {
            return;
        }

        UserFriendRequest userFriendRequest = new UserFriendRequest();
        userFriendRequest.setMyID(otherID);
        userFriendRequest.setOtherID(player.userID);
        int insertRes = GlobalRoot.db.insertIgnore(userFriendRequest);

        if (insertRes > 0) {
            JCEngine.gameService.execute(() -> {
                Player targetPlayer = Player.playerMap.get(otherID);
                if (targetPlayer == null) return;
                targetPlayer.call("onRequestAddFriend");
            });
        }
    }

    /**
     * 是否决定添加好友
     * @param agree 是否同意
    *  @param otherID 目标用户ID
     */
    @SocketMethod(async = true)
    public void decideAddFriend(Player player, boolean agree, int otherID) {
        if (player.userID == otherID) return;  //自己不能添加自己
        UserFriendRequest userFriendRequest = new UserFriendRequest();
        userFriendRequest.setMyID(player.userID);
        userFriendRequest.setOtherID(otherID);
        if (agree) {
            UserFriend userFriend1 = new UserFriend();
            userFriend1.setMyID(player.userID);
            userFriend1.setFriendID(otherID);
            UserFriend userFriend2 = new UserFriend();
            userFriend2.setMyID(otherID);
            userFriend2.setFriendID(player.userID);
            GlobalRoot.db.insertIgnore(userFriend1, userFriend2);
        }
        GlobalRoot.db.delete(userFriendRequest);
    }

    /**
     *  搜索玩家
     */
    @SocketMethod(async = true)
    public void searchPlayers(Player player, SocketResponse socketResponse, String nickname) {
        String sql = new SQL(){
            @Override
            public String toString() {
                return "SELECT id, avatarID, avatarUrl, nickname, offlineTime FROM user_info WHERE nickname = " + PARAM(nickname);
            }
        }.toString();
        List<JSONObject> resList = GlobalRoot.db.select(sql);
        JCEngine.gameService.execute(() -> {
            for (JSONObject jo: resList) {
                int id = jo.getInteger("id");
                jo.put("online", Player.playerMap.get(id) == null ? false : true);
            }
            sortByOnline(resList);
            socketResponse.send(resList);
        });
    }

    /**
     *  搜索玩家
     */
    @SocketMethod(async = true)
    public void searchPlayersByID(Player player, SocketResponse socketResponse, String idStr) {
        int playerID = Integer.parseInt(idStr);
        String sql = "SELECT id, avatarID, avatarUrl, nickname, offlineTime FROM user_info WHERE id = " + playerID + " LIMIT 1";
        List<JSONObject> resList = GlobalRoot.db.select(sql);
        JCEngine.gameService.execute(() -> {
            for (JSONObject jo: resList) {
                int id = jo.getInteger("id");
                jo.put("online", Player.playerMap.get(id) == null ? false : true);
            }
            socketResponse.send(resList);
        });
    }

    @SocketMethod(async = true)
    public void getFriendRecommendList(Player player, SocketResponse socketResponse) {
        SQL sql0 = new SQL(){{
           SELECT("friendID");
           FROM("user_friend");
           WHERE("myID=" + player.userID);
        }};
        List<JSONObject> friendList = GlobalRoot.db.select(sql0);
        List<Integer> friendIDList = new ArrayList<>();
        for (JSONObject item : friendList) {
            friendIDList.add(item.getInteger("friendID"));
        }

        SQL sql1 = new SQL(){{
            SELECT("playerIDSeq");
            SELECT("COUNT(*) as playCount");
            FROM("room_game_record");
            WHERE("(p1ID = " + player.userID + " OR p2ID = " + player.userID + ")");
            if (friendIDList.size() > 0) {
                String notIn = "NOT IN (" + Strings.join(friendIDList, ',') + ")";
                WHERE("(p1ID " + notIn + " AND p2ID " + notIn + ")");
            }
            GROUP_BY("playerIDSeq");
            LIMIT("20");
        }};
        HashMap<Integer, Integer> playCountMap = new HashMap<>();
        List<JSONObject> list1 = GlobalRoot.db.select(sql1);
        for (JSONObject item : list1) {
            String[] idStrList = item.getString("playerIDSeq").split("&");
            //识别出对方的id
            for (String idStr : idStrList) {
                int theID = Integer.parseInt(idStr);
                if (theID != player.userID && theID > 0) {
                    playCountMap.put(theID, item.getInteger("playCount"));
                }
            }
        }
        if (playCountMap.size() > 0) {
            String sql2 = "SELECT id, avatarID, avatarUrl, nickname, offlineTime FROM user_info WHERE id in(" +
                    Strings.join(playCountMap.keySet(), ',') +
                    ")";
            GlobalRoot.db.select(sql2);
            List<JSONObject> resList = GlobalRoot.db.select(sql2);
            for (JSONObject item : resList) {
                item.put("playCount", playCountMap.get(item.get("id")));
            }
            JCEngine.gameService.execute(() -> {
                for (JSONObject jo: resList) {
                    int id = jo.getInteger("id");
                    jo.put("online", Player.playerMap.get(id) == null ? false : true);
                }
                sortByOnline(resList);
                socketResponse.send(resList);
            });
        } else {
            socketResponse.send(new ArrayList<>());
        }
    }

    void sortByOnline(List<JSONObject> list) {
        list.sort((o1, o2) -> {
            boolean o1_online = o1.getBoolean("online");
            boolean o2_online = o2.getBoolean("online");
            if (o1_online && !o2_online) {
                return -1;
            } else if (!o1_online) {
                if (o2_online) {
                    return 1;
                } else {
                    //二级排序
                    long o1_t = o1.getLong("offlineTime");
                    long o2_t = o2.getLong("offlineTime");
                    if (o1_t < o2_t) {
                        return 1;
                    } else if (o1_t > o2_t) {
                        return -1;
                    } else {
                        return 0;
                    }
                }
            } else {
                return 0;
            }
        });
    }
}
