package com.example.demo.module.rank;

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 pers.jc.network.SocketComponent;
import pers.jc.network.SocketMethod;
import pers.jc.network.SocketResponse;
import pers.jc.sql.SQL;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * Socket组件-排行
 */
@SocketComponent("rankComp")
public class RankComp {

    @SocketMethod(async = true)
    public void getFriendRankList(Player player, SocketResponse response) {
        List<UserFriend> userFriendList = GlobalRoot.db.select(UserFriend.class, new SQL(){{
            WHERE("myID = " + player.userID);
            LIMIT("50");
        }});
        List<String> userIdList = new LinkedList<>();
        userIdList.add(String.valueOf(player.userID));
        for (UserFriend uf : userFriendList) {
            userIdList.add(String.valueOf(uf.getFriendID()));
        }
        List<JSONObject> list = GlobalRoot.db.select(new SQL(){{
            SELECT("id");
            SELECT("IFNULL(score," + RankService.ins.getDefaultPkScore() + ") as score");
            SELECT("avatarID");
            SELECT("nickname");
            SELECT("offlineTime");
            FROM("user_info");
            LEFT_OUTER_JOIN("game9_score on id = userID");
            WHERE("id in (" + String.join(",", userIdList) + ")");
            ORDER_BY("score DESC, update_time ASC, id ASC");
        }});
        int rankNum = 0;
        for (JSONObject jo: list) {
            jo.put("rankNum", ++rankNum);
        }
        player.director.callbackHandler.offerCallback(() -> {
            for (JSONObject jo: list) {
                int id = jo.getInteger("id");
                jo.put("online", Player.playerMap.get(id) == null ? false : true);
            }
            response.send(list);
        });
    }

    @SocketMethod(async = true)
    public void getRankList(
            Player player, SocketResponse socketResponse, int rankArea, int rankGameType,
            String countryCode, String stateCode, String cityCode
        ) {
        SQL sqlUtil = new SQL();
        String formatScoreSQL = "IFNULL(score," + RankService.ins.getDefaultPkScore() + ") as score";
        String sqlRankList = "SELECT id, " + formatScoreSQL + ", avatarID, nickname, country FROM user_info LEFT JOIN game"
                + rankGameType + "_score ON userID = id";
        if (rankArea == 1) { //省排行
            sqlRankList += " AND country = " + sqlUtil.PARAM(countryCode);
            sqlRankList += " AND state = " + sqlUtil.PARAM(stateCode);
        } else if (rankArea == 2) { //市排行
            sqlRankList += " AND country = " + sqlUtil.PARAM(countryCode);
            sqlRankList += " AND state = " + sqlUtil.PARAM(stateCode);
            sqlRankList += " AND city = " + sqlUtil.PARAM(cityCode);
        } else {
            //否则为全球排行
        }
        sqlRankList += " ORDER BY score DESC, update_time ASC, id ASC";
        List<JSONObject> rankList = GlobalRoot.db.select(sqlRankList + " Limit 20");
        for (int i = 0; i < rankList.size(); i++) {
            rankList.get(i).put("rankNum", i + 1);
        }
        String sqlMyRank = "SELECT id, score, avatarID, nickname, country, rankNum FROM\n" +
                " (SELECT id, score, avatarID, nickname, country, @rankNum:=@rankNum+1 AS rankNum\n" +
                " FROM (" + sqlRankList + ") a, (SELECT @rankNum:=0) b) c" +
                " WHERE id = " + sqlUtil.PARAM(player.userID);
        List<JSONObject> myRank = GlobalRoot.db.select(sqlMyRank);
        myRank.forEach((a) -> {
            a.put("userID", a.get("id"));
        });
        socketResponse.send(rankList, myRank);
    }

    List<Integer> pkGameTypes = Arrays.asList(new Integer[]{9, 10, 11, 12});
    //PK游戏结果，0：玩家1胜利；1：玩家2胜利；2：双方平局
    List<Integer> pkGameResults = Arrays.asList(new Integer[]{0, 1, 2});
    @SocketMethod(async = true)
    public void uploadPKGameRes(String roomKey, int gameType,
            int p1ID, int p2ID, int gameRes
    ) {
        if (roomKey == null || roomKey.length() != 32) return;
        if (!pkGameTypes.contains(gameType)) return;
        if (!pkGameResults.contains(gameRes)) return;
        boolean res = RankService.ins.insertRoomGameRecord(roomKey, gameType, p1ID, p2ID, gameRes);
        if (!res) return;
        if (!RankService.ins.isRoomNeedCalculatePKScore(roomKey)) return;
        double Ra = RankService.ins.getGameScore(gameType, p1ID);
        double Rb = RankService.ins.getGameScore(gameType, p2ID);
        double Ea = 1 / ( 1 + Math.pow(10, (Rb-Ra)/400d) );
        double Eb = 1 / ( 1 + Math.pow(10, (Ra-Rb)/400d) );
        double Sa;
        double Sb;
        double Ka;
        double Kb;
        if (gameRes == 0) {
            Sa = 1;
            Sb = 0;
            Ka = 32;
            Kb = Rb < 1100 ? 12 : 32;
        } else if (gameRes == 1) {
            Sa = 0;
            Sb = 1;
            Ka = Ra < 1100 ? 12 : 32;
            Kb = 32;
        } else {
            Sa = 0.5;
            Sb = 0.5;
            Ka = 22;
            Kb = 22;
        }
        Ra += Ka * (Sa - Ea);
        Rb += Kb * (Sb - Eb);
        RankService.ins.updateGameScore(gameType, p1ID, (int)Ra);
        RankService.ins.updateGameScore(gameType, p2ID, (int)Rb);
    }
}
