import { Application, BackendSession, ChannelService, HandlerService, } from "pinus";
import { resResult, getRandEelm, getResStr, shouldRefresh, sortArrRandom, checkRoleIsRobot, getRobotSysType, makeRobotId, parseNumberList } from "../../../pubUtils/util";
import { STATUS, ROLE_SELECT, FRIEND_DROP_TYPE, FRIEND_RELATION_TYPE, POPULATE_TYPE, BLOCK_OPEATE, CONSUME_TYPE, ITID, HERO_SELECT, REDIS_KEY, MSG_SOURCE, MSG_TYPE, TASK_TYPE, ROBOT_SYS_TYPE, ITEM_CHANGE_REASON, PUSH_ROUTE } from "../../../consts";
import { RoleModel, RoleType } from "../../../db/Role";
import { getTimeFun, getZeroPointD } from "../../../pubUtils/timeUtil";
import { FriendApplyModel } from "../../../db/FriendApply";
import { FriendListParam, FriendRecommendParams, BlackListParam, FriendValueListParam, HeroDetailParam } from "../../../domain/roleField/friend";
import { FriendShipModel, FriendShipType } from "../../../db/FriendShip";
import { FriendRelationModel, Relation } from "../../../db/FriendRelation";
import { isRoleOnline, getServerName, getRoleOnlineInfo } from "../../../services/redisService";
import { increaseFrdCnt, getRecommendType, sortByBeSentHeart, getApplyList, getFriendList, getMyApplyParam, getMyParamAsFriend } from "../../../services/friendService";
import { FriendPointModel } from "../../../db/FriendPoint";
import { gameData, getDicFriendByLv } from "../../../pubUtils/data";
import { addItems, getFriendPointObject, handleCost } from "../../../services/role/rewardService";
import { RewardInter } from "../../../pubUtils/interface";
import { FriendPresentLogModel } from '../../../db/FriendPresentLog';
import { HeroModel, EPlace } from "../../../db/Hero";
import { FRIEND } from "../../../pubUtils/dicParam";
import { PlayerDetail, PlayerDetailHero } from "../../../domain/battleField/guild";
import { createPrivateMsg, delPrivateMsg, privateRoomId, pushMsgToRole, pushPresent } from "../../../services/chatService";
import { Rank } from "../../../services/rankService";
import { checkTaskWithRoles, checkTask } from "../../../services/task/taskService";
import { ComBattleTeamModel } from "../../../db/ComBattleTeam";
import { JewelModel } from "../../../db/Jewel";
import { getHeroesAttributes } from "../../../services/playerCeService";
import { sendMessageToUsersWithSuc, sendMessageToUserWithSuc } from "../../../services/pushService";
import { PrivateMessageModel } from "../../../db/PrivateMessage";
import { RoleCeModel } from "../../../db/RoleCe";
import { CalCe } from "../../../services/role/calCe";
import { getSchoolPoint } from "../../../services/roleService";
import { LadderMatchModel } from "../../../db/LadderMatch";
import { ArtifactModel } from "../../../db/Artifact";


export default function (app: Application) {
    new HandlerService(app, {});
    return new FriendHandler(app);
}

export class FriendHandler {
    channelService: ChannelService;

    constructor(private app: Application) {
        this.channelService = this.app.get('channelService');
    }

    // 获取推荐好友列表
    public async getRecommend(msg: {}, session: BackendSession) {
        let roleId: string = session.get('roleId');

        const day = <number>getTimeFun().getBeforeHour(FRIEND.FRIEND_RECONMMEND_ACTIVETIME);

        const { lv, serverId: myServerId } = await RoleModel.findByRoleId(roleId, ROLE_SELECT.GET_MY_SERVER);
        let nums = parseNumberList(FRIEND.FRIEND_RECONMMEND_LEVEL);
        let max = Math.max(...nums);
        let allList = await RoleModel.getRecommedList(lv - max, lv + max, day); 
        let sortedNum = nums.sort((a, b) => a - b);
        for(let num of sortedNum) {
            allList = allList.filter(cur => cur.lv >= lv - num && cur.lv <= lv + num);
            if(allList.length > 0) break;
        }

        // 筛掉自己今天申请过的人
        let applyList = await FriendApplyModel.getSentApplyList(roleId, getZeroPointD());
        allList = allList.filter(cur => {
            return !applyList.find(ccur => ccur.roleId == cur.roleId);
        });

        let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.NOT);

        let myServerList = new Array<FriendRecommendParams>();
        let otherServerList = new Array<FriendRecommendParams>();
        for (let role of allList) {
            let type = getRecommendType(myFriendRelation, roleId, role.roleId);
            if (type == FRIEND_RELATION_TYPE.NORMAL) {
                let param = new FriendRecommendParams(role);
                param.setType(type);

                let { serverId } = role;
                let serverName = await getServerName(serverId);
                param.setServerName(serverId, serverName);

                if (myServerId == serverId) {
                    myServerList.push(param);
                } else {
                    otherServerList.push(param);
                }

            }
        }

        // 前4个是本服的，后4个随意，优先本服，其他补上
        let myServerLen = myServerList.length > FRIEND.FRIEND_RECONMMEND_SERVICE ? FRIEND.FRIEND_RECONMMEND_SERVICE : myServerList.length;
        let list1: FriendRecommendParams[] = getRandEelm(myServerList, myServerLen);

        let otherServerLen = otherServerList.length > FRIEND.FRIEND_RECONMMEND_NUM - myServerLen ? FRIEND.FRIEND_RECONMMEND_NUM - myServerLen : otherServerList.length;
        let list2: FriendRecommendParams[] = getRandEelm(otherServerList, otherServerLen);

        if (list2.length < FRIEND.FRIEND_RECONMMEND_NUM - myServerLen) {
            if (myServerList.length <= FRIEND.FRIEND_RECONMMEND_NUM - list2.length) {
                list1 = myServerList;
            } else {
                list1 = getRandEelm(myServerList, FRIEND.FRIEND_RECONMMEND_NUM - list2.length);
            }
        }
        list1 = sortArrRandom(list1);
        list2 = sortArrRandom(list2);

        let list = list1.concat(list2);

        return resResult(STATUS.SUCCESS, { list });
    }

    // 搜索好友
    public async searchUser(msg: { value: string }, session: BackendSession) {
        let roleId: string = session.get('roleId');

        let { value } = msg;
        let allList = await RoleModel.searchByNameOrId(value);
        let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.NOT);

        let list = new Array<FriendRecommendParams>();
        for (let role of allList) {
            let type = getRecommendType(myFriendRelation, roleId, role.roleId);
            let param = new FriendRecommendParams(role);
            param.setType(type);

            let { serverId } = role;
            let serverName = await getServerName(serverId);
            param.setServerName(serverId, serverName);

            list.push(param);
        }

        return resResult(STATUS.SUCCESS, { list });
    }

    // 申请
    public async applyFriend(msg: { roleIds: string[] }, session: BackendSession) {
        let roleId: string = session.get('roleId');
        let roleIds = msg.roleIds;

        const role = await RoleModel.findByRoleId(roleId, ROLE_SELECT.GET_ROLE_ID);
        let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.NOT);

        let str = '', resultRoleIds = new Array<string>();
        for (let hisRoleId of roleIds) {
            let type = getRecommendType(myFriendRelation, roleId, hisRoleId);
            if (type == FRIEND_RELATION_TYPE.HAS_FRIEND) {
                str = getResStr(STATUS.FRIEND_HAS_ADD); continue;
            } else if (type == FRIEND_RELATION_TYPE.HAS_BLOCKED) {
                str = getResStr(STATUS.FRIEND_HAS_BLOCKED); continue;
            } else if (type == FRIEND_RELATION_TYPE.MYSELF) {
                str = getResStr(STATUS.FRIEND_YOURSELF); continue;
            }
            let hisRelation = await FriendRelationModel.findFriendByRole(hisRoleId, POPULATE_TYPE.NOT);
            let hisType = getRecommendType(hisRelation, hisRoleId, roleId);
            if(hisType == FRIEND_RELATION_TYPE.NORMAL) {
                let incResult = await RoleModel.increaseFriendApplyCnt(hisRoleId, 1, FRIEND.FRIEND_MANAGE_APPLICATION);
                if (!incResult) {
                    str = getResStr(STATUS.FRIEND_HIS_APPLY_MAX); continue;
                }
    
                let apply = await FriendApplyModel.createApply(hisRoleId, role);
                resultRoleIds.push(hisRoleId);
                let hisOnlineInfo = await getRoleOnlineInfo(hisRoleId);
                if (hisOnlineInfo.isOnline) {
                    let myApply = await getMyApplyParam(apply.applyCode, role);
                    sendMessageToUserWithSuc(hisRoleId, PUSH_ROUTE.FRIEND_APPLY, { apply: myApply }, hisOnlineInfo.sid);
                }
            }
        }

        return resResult(STATUS.SUCCESS, {
            isSuccess: str == '',
            msg: str,
            roleIds: resultRoleIds
        });
    }

    // 获取申请列表
    public async getApplyList(msg: {}, session: BackendSession) {

        let roleId: string = session.get('roleId');
        let result = await getApplyList(roleId);
        return resResult(STATUS.SUCCESS, {
            list: result
        });
    }

    // （一键）同意/拒绝申请
    public async handleApply(msg: { applyCodeList: string[], isPass: boolean }, session: BackendSession) {
        let roleId: string = session.get('roleId');
        let sid: string = session.get('sid');
        
        const serverId = session.get('serverId');

        let { applyCodeList, isPass } = msg;

        let role = await RoleModel.findByRoleId(roleId);
        let roles = new Array<RoleType>();
        let friendCnt = role.friendCnt;

        let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.NOT);

        let applyList = await FriendApplyModel.getApplyListByCode(applyCodeList);
        let list = new Array<FriendListParam>();

        let str = '', resultApplyCodeList = new Array<string>();
        if (isPass) {
            for (let apply of applyList) {
                let type = getRecommendType(myFriendRelation, roleId, apply.frdRoleId);
                if (type == FRIEND_RELATION_TYPE.HAS_FRIEND) {
                    str = getResStr(STATUS.FRIEND_HAS_ADD);
                    resultApplyCodeList.push(apply.applyCode); continue;
                } else if (type == FRIEND_RELATION_TYPE.HAS_BLOCKED) {
                    resultApplyCodeList.push(apply.applyCode);
                    str = getResStr(STATUS.FRIEND_HAS_BLOCKED); continue;
                } else if (type == FRIEND_RELATION_TYPE.MYSELF) {
                    resultApplyCodeList.push(apply.applyCode);
                    str = getResStr(STATUS.FRIEND_YOURSELF); continue;
                }

                // 好友数量校验
                let friend = <RoleType>apply.friend;
                str = await increaseFrdCnt(role, friend, friendCnt);
                if (str != '') continue;
                roles.push(friend);

                // 创建friendShip
                let friendShip = await FriendShipModel.createFriendShip([roleId, friend.roleId]);
                if (!friendShip) {
                    str = getResStr(STATUS.FRIEND_SHIP_CREATE_ERROR); continue;
                }

                await FriendRelationModel.addFriend(roleId, friend, friendShip);
                await FriendRelationModel.addFriend(friend.roleId, role, friendShip);

                let param = new FriendListParam(friend, roleId, friendShip);
                let hisOnlineInfo = await getRoleOnlineInfo(friend.roleId);
                param.setOnline(hisOnlineInfo.isOnline);

                let { serverId } = friend;
                let serverName = await getServerName( serverId);
                param.setServerName(serverId, serverName);

                param.setType(FRIEND_RELATION_TYPE.HAS_FRIEND);
                list.push(param);
                if (hisOnlineInfo.isOnline) {
                    let myParam = await getMyParamAsFriend(friendShip, role, friend.roleId);
                    sendMessageToUserWithSuc(friend.roleId, PUSH_ROUTE.FRIEND_ADD, { friend: myParam }, hisOnlineInfo.sid);
                }

                resultApplyCodeList.push(apply.applyCode);
            }
        } else {
            resultApplyCodeList = applyCodeList;
        }

        let deleteCount = await FriendApplyModel.deleteApply(resultApplyCodeList);
        role = await RoleModel.increaseFriendApplyCnt(roleId, -1 * deleteCount, FRIEND.FRIEND_MANAGE_APPLICATION);
        roles.push(role);
        // 任务
        await checkTaskWithRoles(roleId, sid, TASK_TYPE.FRIEND_NUM, roles);

        // 特殊处理：如果他点一键同意，有很多人，这个单独的人就不做这个额外的提示，直接把他好友申请删掉就好
        if (str == getResStr(STATUS.FRIEND_HAS_ADD) && resultApplyCodeList.length > 1) str = '';

        return resResult(STATUS.SUCCESS, {
            isSuccess: str == '',
            msg: str,
            applyCodeList: resultApplyCodeList,
            list,
            friendCnt
        });
    }

    // 获取好友列表
    public async getFriendList(msg: {}, session: BackendSession) {
        let roleId: string = session.get('roleId');

        let role = await RoleModel.findByRoleId(roleId);
        let res = await getFriendList(role);

        return resResult(STATUS.SUCCESS, res);
    }

    // 获取黑名单
    public async getBlackList(msg: {}, session: BackendSession) {
        let roleId: string = session.get('roleId');

        let role = await RoleModel.findByRoleId(roleId);
        let list = new Array<BlackListParam>();
        let myRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.BLACKLIST);
        let blacklist = myRelation ? myRelation.blacklist : [];
        for (let bl of blacklist) {
            let friendRole = <RoleType>bl.role;
            if (!friendRole) continue;
            let param = new BlackListParam(friendRole);
            let isOnline = await isRoleOnline(friendRole.roleId);
            param.setOnline(isOnline);

            let { serverId } = friendRole;
            let serverName = await getServerName(serverId);
            param.setServerName(serverId, serverName);

            param.setType(FRIEND_RELATION_TYPE.HAS_BLOCKED);

            list.push(param);

        }

        let { friendCnt = 0, blockCnt = 0 } = role;

        return resResult(STATUS.SUCCESS, {
            list,
            friendCnt, blockCnt
        });
    }


    // 拉黑/移除
    public async setBlackList(msg: { roleId: string, type: number }, session: BackendSession) {
        let roleId: string = session.get('roleId');
        let sid: string = session.get('sid');
        
        const serverId = session.get('serverId');
        let { roleId: hisRoleId, type } = msg;

        let role = await RoleModel.findByRoleId(roleId);
        let friend: RoleType;

        let str = '', list = new Array<BlackListParam>(), frdRoleIds = new Array<string>(), blackRoleIds = new Array<string>();
        if (type == BLOCK_OPEATE.ADD) { // 拉黑
            let myRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.FRIEND);
            let friends = myRelation ? myRelation.friends : [];
            let blacklist = myRelation ? myRelation.blacklist : [];
            let curFriend = friends.find(cur => cur.roleId == hisRoleId);
            let curBlack = blacklist.find(cur => cur.roleId == hisRoleId);
            if (curBlack) {
                return resResult(STATUS.FRIEND_BLACK_HAS_ADD);
            }

            role = await RoleModel.increaseBlockCnt(roleId, 1, curFriend ? -1 : 0, FRIEND.FRIEND_BLACKLIST_MAX); // 增加黑名单人数
            if (!role) {
                return resResult(STATUS.FRIEND_BLACK_MAX)
            }
            friend = await RoleModel.increaseFriendCnt(hisRoleId, curFriend ? -1 : 0); // 对方好友减少

            let friendShip: FriendShipType;
            if (!!curFriend) {
                await FriendShipModel.clearValue([roleId, hisRoleId]);
                friendShip = <FriendShipType>curFriend.friendShip;
            }

            await FriendRelationModel.moveFromFriend(hisRoleId, role, friendShip, false, !!curFriend); //从对方好友删除
            await FriendRelationModel.moveFromFriend(roleId, friend, friendShip, true, !!curFriend); // 删除好友关系并拉黑
            await PrivateMessageModel.blockMsg(privateRoomId(roleId, hisRoleId)); // 屏蔽掉双方对话
            await delPrivateMsg(roleId, hisRoleId);

            let { myRecApplyCount, hisRecApplyCount } = await FriendApplyModel.deleteApplyByRoles(roleId, hisRoleId); // 删除双方的申请
            if(myRecApplyCount > 0) await RoleModel.increaseFriendApplyCnt(roleId, -1 * myRecApplyCount, FRIEND.FRIEND_MANAGE_APPLICATION);
            if(hisRecApplyCount > 0) await RoleModel.increaseFriendApplyCnt(roleId, -1 * hisRecApplyCount, FRIEND.FRIEND_MANAGE_APPLICATION);

            let param = new BlackListParam(friend);
            let { isOnline, sid } = await getRoleOnlineInfo(friend.roleId);

            if(isOnline && (!!curFriend || myRecApplyCount > 0 || hisRecApplyCount > 0)) { // 当你们双方为好友，或者你申请过她的好友，拉黑的时候通知一下他删列表
                await sendMessageToUserWithSuc(friend.roleId, PUSH_ROUTE.SET_BLACK, { blackRoleIds: [roleId] }, sid);
            }


            param.setOnline(isOnline);

            let { serverId } = friend;
            let serverName = await getServerName(serverId);
            param.setServerName(serverId, serverName);

            param.setType(FRIEND_RELATION_TYPE.HAS_BLOCKED);
            list.push(param);
            frdRoleIds.push(hisRoleId);
        } else if (type == BLOCK_OPEATE.REMOVE_FRIEND) { // 仅移除

            let myRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.FRIEND);
            let friends = myRelation ? myRelation.friends : [];
            let curFriend = friends.find(cur => cur.roleId == hisRoleId);
            if (!curFriend) {
                return resResult(STATUS.FRIEND_NOT_FOUND);
            }

            role = await RoleModel.increaseFriendCnt(roleId, -1); // 减少好友
            if (!role) {
                return resResult(STATUS.FRIEND_NOT_FOUND)
            }
            friend = await RoleModel.increaseFriendCnt(hisRoleId, -1); // 对方好友减少

            let friendShip: FriendShipType;

            await FriendShipModel.clearValue([roleId, hisRoleId]);
            friendShip = <FriendShipType>curFriend.friendShip;

            await FriendRelationModel.moveFromFriend(hisRoleId, role, friendShip, false, !!curFriend); //从对方好友删除
            await FriendRelationModel.moveFromFriend(roleId, friend, friendShip, false, !!curFriend); // 删除好友关系并拉黑

            frdRoleIds.push(hisRoleId);

        } else if (type == BLOCK_OPEATE.REMOVE_BLACK || type == BLOCK_OPEATE.REMOVE_AND_APPLY) {
            let myRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.BLACKLIST);
            let blacklist = myRelation ? myRelation.blacklist : [];

            let curFriend = blacklist.find(cur => cur.roleId == hisRoleId);
            if (!curFriend) {
                return resResult(STATUS.FRIEND_BLACK_NOT_FOUND);
            }

            role = await RoleModel.increaseBlockCnt(roleId, -1, 0, 100); // 黑名单人数减            
            if (!role) {
                return resResult(STATUS.FRIEND_BLACK_MAX)
            }
            await FriendRelationModel.removeFromBlack(roleId, hisRoleId);

            if (type == BLOCK_OPEATE.REMOVE_AND_APPLY) {
                // 申请好友
                friend = await RoleModel.increaseFriendApplyCnt(hisRoleId, 1, FRIEND.FRIEND_MANAGE_APPLICATION);
                if (!friend) {
                    str = getResStr(STATUS.FRIEND_HIS_APPLY_MAX);
                } else {
                    let hisRelation = await FriendRelationModel.findFriendByRole(hisRoleId, POPULATE_TYPE.NOT);
                    let hisType = getRecommendType(hisRelation, hisRoleId, roleId);
                    if(hisType == FRIEND_RELATION_TYPE.NORMAL) {
                        let incResult = await RoleModel.increaseFriendApplyCnt(hisRoleId, 1, FRIEND.FRIEND_MANAGE_APPLICATION);
                        if (incResult) {
                            let apply = await FriendApplyModel.createApply(hisRoleId, role);
                            let hisOnlineInfo = await getRoleOnlineInfo(hisRoleId);
                            if(hisOnlineInfo) {
                                let myApply = await getMyApplyParam(apply.applyCode, role);
                                sendMessageToUserWithSuc(friend.roleId, PUSH_ROUTE.FRIEND_APPLY, { apply: myApply }, hisOnlineInfo.sid);
                            }                     
                        }
                    }
                }
            }
            blackRoleIds.push(hisRoleId);

        } else {
            return resResult(STATUS.WRONG_PARMS);
        }

        let { friendCnt = 0, blockCnt = 0 } = role;

        // 任务
        await checkTaskWithRoles(roleId, sid, TASK_TYPE.FRIEND_NUM, [role, friend]);
        return resResult(STATUS.SUCCESS, {
            frdRoleIds, blackRoleIds,
            isSuccess: str == '',
            msg: str,
            list,
            friendCnt, blockCnt
        });
    }

    // 赠送爱心/一键赠送
    public async sendHeart(msg: { roleId: string }, session: BackendSession) {
        let roleId: string = session.get('roleId');
        let roleName: string = session.get('roleName');
        let sid: string = session.get('sid');
        let serverId: number = session.get('serverId');
        

        let { roleId: hisRoleId } = msg;

        let myRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.FRIEND); // 好友关系，只有friendship被populate了
        let friends = myRelation ? myRelation.friends : [];
        let arr = new Array<Relation>();
        if (hisRoleId != '') {
            let cur = friends.find(cur => cur.roleId == hisRoleId);
            if (!cur) return resResult(STATUS.FRIEND_NOT_FOUND);

            arr.push(cur);
        } else {
            arr = friends;
        }
        let canSendList = await sortByBeSentHeart(roleId, arr);

        let { lv } = await RoleModel.findByRoleId(roleId, ROLE_SELECT.GET_LV);
        let dicFriendLv = getDicFriendByLv(lv);
        if (!dicFriendLv) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        // 情谊值有上限，送到上限为止
        let max = dicFriendLv.sendMax;
        let frdPointRec = await FriendPointModel.getFrdPointRecToday(roleId, FRIEND_DROP_TYPE.SEND_GIFT);
        let { sendCnt: todaySendCnt = 0 } = frdPointRec || {};

        let todaySendInc = 0;
        let list = new Array<FriendValueListParam>();

        let uids = [];
        for (let relation of canSendList) {

            if (todaySendCnt + FRIEND.FRIEND_FRIENDPOINT_ADD > max) break;
            let fs = <FriendShipType>relation.friendShip;
            let ref = shouldRefresh(fs.refTime, new Date());
            let sendHeartRec = await FriendShipModel.sendHeart(roleId, relation.roleId, 1, FRIEND.FRIEND_RECEIVE_SINGLE, ref);
            if (!sendHeartRec) continue;

            let param = new FriendValueListParam(relation.roleId, roleId, sendHeartRec);
            list.push(param);

            todaySendCnt += FRIEND.FRIEND_FRIENDPOINT_ADD;
            todaySendInc += FRIEND.FRIEND_FRIENDPOINT_ADD;

            let hisOnlineInfo = await getRoleOnlineInfo(relation.roleId);
            if (hisOnlineInfo.isOnline) {
                uids.push({ uid: relation.roleId, sid: hisOnlineInfo.sid });
            }
        }

        sendMessageToUsersWithSuc(PUSH_ROUTE.FRIEND_SEND_HEART, { roleId }, uids);
        if (todaySendInc <= 0) return resResult(STATUS.FRIEND_HAS_SENT);

        // 更新情谊值
        frdPointRec = await FriendPointModel.updateSendCntToday(roleId, roleName, todaySendInc, max, FRIEND_DROP_TYPE.SEND_GIFT);
        // 活动任务
        if (todaySendInc > 0) {
            await checkTask(serverId, roleId, sid, TASK_TYPE.FRIEND_SEND_HEART, { count: todaySendInc });
        }

        return resResult(STATUS.SUCCESS, {
            todaySendCnt, list
        })
    }


    // 领取爱心/一键领取
    public async receiveHeart(msg: { roleId: string }, session: BackendSession) {
        let roleId: string = session.get('roleId');
        let roleName: string = session.get('roleName');
        let sid: string = session.get('sid');

        let { roleId: hisRoleId } = msg;

        let myRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.FRIEND); // 好友关系，只有friendship被populate了
        let friends = myRelation ? myRelation.friends : [];
        let arr = new Array<Relation>();
        if (hisRoleId != '') {
            let cur = friends.find(cur => cur.roleId == hisRoleId);
            if (!cur) return resResult(STATUS.FRIEND_NOT_FOUND);

            arr.push(cur);
        } else {
            arr = friends;
        }
        let canReceiveList = await sortByBeSentHeart(roleId, arr);

        let { lv } = await RoleModel.findByRoleId(roleId, ROLE_SELECT.GET_LV);
        let dicFriendLv = getDicFriendByLv(lv);
        if (!dicFriendLv) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        // 情谊值有上限，到上限为止
        let max = dicFriendLv.receiveMax;
        let frdPointRec = await FriendPointModel.getFrdPointRecToday(roleId, FRIEND_DROP_TYPE.SEND_GIFT);
        let { cnt: todayReceiveCnt = 0 } = frdPointRec || {};

        let todayReceiveInc = 0;
        let list = new Array<FriendValueListParam>();
        for (let relation of canReceiveList) {
            if (relation.beSentHeart > 0) {
                if (todayReceiveCnt + FRIEND.FRIEND_FRIENDPOINT_ADD > max) break;

                // 收取爱心
                let fs = <FriendShipType>relation.friendShip;
                let ref = shouldRefresh(fs.refTime, new Date());
                let receiveHeartRec = await FriendShipModel.receiveHeart(roleId, relation.roleId, 1, relation.beSentHeart, ref);
                if (!receiveHeartRec) continue;

                let param = new FriendValueListParam(relation.roleId, roleId, receiveHeartRec);
                list.push(param);

                todayReceiveCnt += FRIEND.FRIEND_FRIENDPOINT_ADD;
                todayReceiveInc += FRIEND.FRIEND_FRIENDPOINT_ADD;
            }
        }
        if (todayReceiveInc <= 0) return resResult(STATUS.FRIEND_HAS_RECEIVE);
        let fp = getFriendPointObject(todayReceiveInc);
        let goods = await addItems(roleId, roleName, sid, [fp], ITEM_CHANGE_REASON.RECEIVE_FRIEND_HEART)

        frdPointRec = await FriendPointModel.updatePointToday(roleId, roleName, todayReceiveInc, max, FRIEND_DROP_TYPE.SEND_GIFT);

        return resResult(STATUS.SUCCESS, {
            simpleGoods: goods,
            todayReceiveCnt, list
        })
    }

    // 赠送礼物
    public async sendPresent(msg: { roleId: string, items: RewardInter[] }, session: BackendSession) {
        let roleId: string = session.get('roleId');
        let roleName: string = session.get('roleName');
        let sid: string = session.get('sid');
        let serverId: string = session.get('serverId');

        let { roleId: hisRoleId, items } = msg;
        let myRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.FRIEND_NAME_ONLY);
        let friends = myRelation ? myRelation.friends : [];
        let curFriend = friends.find(cur => cur.roleId == hisRoleId);
        if (!curFriend) return resResult(STATUS.FRIEND_NOT_FOUND);

        let friendValueInc = 0;
        for (let { id, count } of items) {
            let dicGood = gameData.goods.get(id);
            if (!dicGood) {
                return resResult(STATUS.DIC_DATA_NOT_FOUND);
            }

            let dicItid = ITID.get(dicGood.itid);
            if (dicItid.type == CONSUME_TYPE.FRIEND_FAVOUR) {
                friendValueInc += dicGood.value * count;
            } else {
                return resResult(STATUS.WRONG_PARMS);
            }
        }

        let costResult = await handleCost(roleId, sid, items, ITEM_CHANGE_REASON.FRIEND_SEND_PRESENT);
        if (!costResult) return resResult(STATUS.ROLE_MATERIAL_NOT_ENOUGH);

        let result = await FriendShipModel.addFriendValue(roleId, hisRoleId, friendValueInc);
        if (!result) return resResult(STATUS.FRIEND_NOT_FOUND);

        await FriendPresentLogModel.createRecord(roleId, hisRoleId, items);
        for (let { id, count } of items) {
            let relation = getRecommendType(myRelation, roleId, hisRoleId);
            const msgData = await createPrivateMsg(roleId, roleName, MSG_TYPE.RICH_TEXT, MSG_SOURCE.PRIVATE_SEND_GIFT, JSON.stringify({ id, count }), hisRoleId, null, relation);
            await pushMsgToRole(msgData);
            // let hisRole = <RoleType>curFriend.role;
            // await pushPresent(roleId, roleName, serverId, hisRole.roleName, id);
        }

        return resResult(STATUS.SUCCESS, {
            roleId: hisRoleId,
            ...result
        });
    }

    async getPlayerSimpleInfo(msg: { roleId: string }, session: BackendSession) {

        let roleId: string = session.get('roleId');

        let { roleId: targetRoleId } = msg;
        let isRobot = checkRoleIsRobot(targetRoleId);
        if(isRobot) {
            let role = await RoleModel.findByRoleId(roleId, null, true);
            let sysType = getRobotSysType(targetRoleId);
            let addObj: any = { roleId: makeRobotId(''), roleName: '', guildName: '' };
            if(sysType == ROBOT_SYS_TYPE.COM_BTL) {
                let comBattle = await ComBattleTeamModel.findByRoleId(targetRoleId);
                if(comBattle) {
                    addObj = comBattle.roleStatus.find(cur => cur.roleId == targetRoleId)||{};
                }
            }
            let param = new FriendRecommendParams({...role, ...addObj});
            param.setType(FRIEND_RELATION_TYPE.ROBOT);
            let { serverId } = role;
            let serverName = await getServerName(serverId);
            param.setServerName(serverId, serverName);

            return resResult(STATUS.SUCCESS, {...param, isRobot });
        } else {

            let role = await RoleModel.findByRoleId(targetRoleId, null, true);
            let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.NOT);

            let type = getRecommendType(myFriendRelation, roleId, role.roleId);
            let param = new FriendRecommendParams(role);
            param.setType(type);

            let { serverId } = role;
            let serverName = await getServerName(serverId);
            param.setServerName(serverId, serverName);
            return resResult(STATUS.SUCCESS, {...param, isRobot });
        }

    }

    async getPlayerDetail(msg: { roleId: string }, session: BackendSession) {

        // let roleId = session.get('roleId');
        let { roleId: oppoRoleId } = msg;

        let result: PlayerDetail;

        let dbHeroes = await HeroModel.findByRole(oppoRoleId);
        let role = await RoleModel.findByRoleId(oppoRoleId, null, true);
        if(!role) return resResult(STATUS.ROLE_NOT_FOUND);

        let { topLineup, topLineupCe, towerLv, showLineup } = role;

        let heroes = new Array<PlayerDetailHero>();

        if (showLineup && showLineup.length) { // 设置过展示阵容
            for (let hid of showLineup) {
                let curHero = dbHeroes.find(cur => cur.hid == hid);
                if (curHero) {
                    let hero = new PlayerDetailHero();
                    hero.setByDbHero(curHero);
                    heroes.push(hero);
                }
            }
        } else {
            for (let { hid } of topLineup) {
                let curHero = dbHeroes.find(cur => cur.hid == hid);
                if (curHero) {
                    let hero = new PlayerDetailHero();
                    hero.setByDbHero(curHero);
                    heroes.push(hero);
                }
            }
        }

        let ladder = await LadderMatchModel.findByRoleId(oppoRoleId);

        result = new PlayerDetail(oppoRoleId, heroes);
        result.setPlayer(role);
        result.setCe(topLineupCe);
        result.setWarStar(role.warStar, ladder?.rank||0, towerLv - 1);

        return resResult(STATUS.SUCCESS, result);
    }

    // 查看对象武将详细
    public async getHeroDetail(msg: { roleId: string, hids: number[] }, session: BackendSession) {
        // let roleId: string = session.get('roleId');
        // let sid: string = session.get('sid');

        let { roleId: hisRoleId, hids } = msg;

        let role = await RoleModel.findByRoleId(hisRoleId, 'title');
        if (!role) return resResult(STATUS.ROLE_NOT_FOUND);
    
        let roleCe = await RoleCeModel.findByRoleId(hisRoleId);
        if (!roleCe) return resResult(STATUS.ROLE_NOT_FOUND);

        let heroList = await HeroModel.findByHidRange(hids, hisRoleId, HERO_SELECT.HERO_DETAIL, true);
        if (heroList.length <= 0) return resResult(STATUS.HERO_NOT_FIND);

        let jewels = await JewelModel.findMapbyRoleAndHids(hisRoleId, hids);

        let school = await getSchoolPoint(hisRoleId);

        let calCe = new CalCe(hisRoleId);
        calCe.setRoleCe(roleCe);
        let attrByHid = await getHeroesAttributes(hisRoleId);
        let list: HeroDetailParam[] = [];
        for (let hero of heroList) {
            let attr = attrByHid.get(hero.hid);
            if(!attr) continue;
            let attributes = attr.getMainAttributes();
            let heroParam = new HeroDetailParam(hero);
            heroParam.setAttributes(attributes);
            heroParam.setJewels(jewels);
            if(hero.artifact > 0) {
                let artifact = await ArtifactModel.findbySeqId(hisRoleId, hero.artifact);
                if(artifact) heroParam.setArtifact(artifact);
            }

            heroParam.setRole(
                role.title,
                calCe.calSingleGlobalPartCe(hero.hid, 'scroll'),
                calCe.calSingleGlobalPartCe(hero.hid, 'teraph'),
                school
            );

            list.push(heroParam);
        }


        return resResult(STATUS.SUCCESS, { list });
    }

}