import { gameData, getDicFriendByLv } from "../pubUtils/data";
import { RoleType, RoleModel } from "../db/Role";
import { FriendRelationType, Relation, FriendRelationModel } from "../db/FriendRelation";
import { getResStr, shouldRefresh } from "../pubUtils/util";
import { STATUS, FRIEND_RELATION_TYPE, POPULATE_TYPE, FRIEND_DROP_TYPE } from "../consts";
import { FriendShipType, FriendShipModel } from "../db/FriendShip";
import { outputCnt } from '../pubUtils/friendUtil';
import { isRoleOnline, getServerName, getRoleOnlineInfo } from "./redisService";
import { FriendApplyModel } from "../db/FriendApply";
import { FriendApplyParams, FriendListParam } from "../domain/roleField/friend";
import { FRIEND } from "../pubUtils/dicParam";
import { FriendPointModel } from "../db/FriendPoint";

export async function getFriendList(role: RoleType) {
    let { roleId } = role;
    let list = new Array<FriendListParam>();
    let myRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.FRIEND);
    let friendList = myRelation ? myRelation.friends : [];

    for (let friend of friendList) {
        let friendRole = <RoleType>friend.role;
        let friendShip = <FriendShipType>friend.friendShip;
        if (!friendRole || !friendShip) continue;

        let fs = <FriendShipType>friend.friendShip;
        let ref = shouldRefresh(fs.refTime, new Date());
        if (ref) {
            friendShip = await FriendShipModel.refreshSendAndReceive(roleId, friendRole.roleId);
        }

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

        let isOnline = await isRoleOnline(friendRole.roleId);
        param.setOnline(isOnline);

        param.setType(FRIEND_RELATION_TYPE.HAS_FRIEND);

        list.push(param);
    }

    list.sort((a, b) => {
        if (a.isOnline != b.isOnline) {
            return a.isOnline ? 1 : -1
        }
        if (a.quitTime != b.quitTime) {
            return b.quitTime - a.quitTime
        }
        return a.friendValue - b.friendValue;
    });

    let { friendCnt = 0, blockCnt = 0 } = role;
    let frdPointRec = await FriendPointModel.getFrdPointRecToday(roleId, FRIEND_DROP_TYPE.SEND_GIFT);
    let { cnt: todayReceiveCnt = 0, sendCnt: todaySendCnt = 0 } = frdPointRec || {};
    
    return {  
        todayReceiveCnt,
        todaySendCnt,
        list,
        friendCnt, blockCnt
    }
}

/**
 * 获取玩家申请列表
 * @param roleId 玩家id
 */
export async function getApplyList(roleId: string) {
    let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.NOT);
    let list = await FriendApplyModel.getApplyList(roleId);
    let result = new Array<FriendApplyParams>();
    let delApplyCodeList = new Array<string>();
    for (let apply of list) {
        let friend = <RoleType>apply.friend;
        let type = getRecommendType(myFriendRelation, roleId, friend.roleId);

        let param = new FriendApplyParams(apply.applyCode, friend);

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

        param.setType(type);
        if (type != FRIEND_RELATION_TYPE.NORMAL) {
            delApplyCodeList.push(apply.applyCode);
            continue;
        }

        result.push(param);
    }
    let deleteCount = await FriendApplyModel.deleteApply(delApplyCodeList);
    await RoleModel.increaseFriendApplyCnt(roleId, -1 * deleteCount, FRIEND.FRIEND_MANAGE_APPLICATION);
    return result;
}

export async function getMyApplyParam(applyCode: string, role: RoleType) {
    let param = new FriendApplyParams(applyCode, role);

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


export async function getMyParamAsFriend(friendShip: FriendShipType, role: RoleType, friendRoleId: string) {
    let param = new FriendListParam(role, friendRoleId, friendShip);
    let hisOnlineInfo = await getRoleOnlineInfo(role.roleId);
    param.setOnline(hisOnlineInfo.isOnline);

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

    param.setType(FRIEND_RELATION_TYPE.HAS_FRIEND);
    return param;
}

/**
 * 增加双方好友数
 * @param role1 我方
 * @param role2 对方
 * @returns 是否添加成功
 */
export async function increaseFrdCnt(role1: RoleType, role2: RoleType, originalFriendCnt: number) {
 
    let { roleId, lv, friendCnt } = role1;
    let dicFriend =  getDicFriendByLv(lv);
    if(friendCnt >= dicFriend.frdCnt) return getResStr(STATUS.FRIEND_MY_CNT_MAX);

    let { roleId: _roleId, lv: _lv, friendCnt: _friendCnt } = role2;
    let _dicFriend = getDicFriendByLv(_lv);
    if(_friendCnt >= _dicFriend.frdCnt) return getResStr(STATUS.FRIEND_THEY_CNT_MAX);

    let incMyFrdCnt = await RoleModel.increaseFriendCnt(roleId, 1, dicFriend.frdCnt);
    if(!incMyFrdCnt) return getResStr(STATUS.FRIEND_MY_CNT_MAX);
    let incHisFrdCnt = await RoleModel.increaseFriendCnt(_roleId, 1, _dicFriend.frdCnt);
    if(!incHisFrdCnt) { // 回滚
        await RoleModel.increaseFriendCnt(roleId, -1, dicFriend.frdCnt);
        return getResStr(STATUS.FRIEND_THEY_CNT_MAX);
    }
    originalFriendCnt = incMyFrdCnt.friendCnt;
    role1.friendCnt = incMyFrdCnt.friendCnt; 
    role2.friendCnt = incHisFrdCnt.friendCnt;

    return '';
}

export async function getFriendRelationType(myRoleId: string, roleId: string) {
    let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.NOT);
    return getRecommendType(myFriendRelation, roleId, myRoleId);
}

export function getRecommendType(myFriendRelation: FriendRelationType, myRoleId: string, roleId: string) {
    if(myRoleId == roleId) {
        return FRIEND_RELATION_TYPE.MYSELF;
    }
    let friendList = myFriendRelation? myFriendRelation.friends: [];
    let blackList = myFriendRelation? myFriendRelation.blacklist: [];
    let hasFriend = friendList.find(cur => cur.roleId == roleId);
    if(hasFriend) {
        return FRIEND_RELATION_TYPE.HAS_FRIEND;
    }
    let hasBlcklist = blackList.find(cur => cur.roleId == roleId);
    if(hasBlcklist) {
        return FRIEND_RELATION_TYPE.HAS_BLOCKED;
    }
    return FRIEND_RELATION_TYPE.NORMAL;
}

/**
 * 根据收到的新及时间排序
 * 
 * @param roleId 自己的玩家id 
 * @param list 需要排序列表
 */
export async function sortByBeSentHeart(roleId: string, list: Relation[]) {

    let result = new Array<Relation & {beSentHeart: number, beSentHeartTime: number} & { quitTime: number, friendValue: number, isOnline: boolean}>();
    for(let cur of list) {
        let json = getSentHeart(roleId, cur);
        let friendRole = <RoleType>cur.role;
        let friendShip = <FriendShipType>cur.friendShip;
        let isOnline = await isRoleOnline(friendRole.roleId);
        result.push({...cur, ...json, isOnline, quitTime: friendRole.quitTime, friendValue: friendShip.friendValue});
    }
    
    result.sort((a, b) => {
        if(a.beSentHeart && b.beSentHeart) { // 只要有一方送过
            if(a.beSentHeart == b.beSentHeart) {
                return a.beSentHeartTime - b.beSentHeartTime;
            } else {
                return b.beSentHeart - a.beSentHeart;
            }
        } else { // 都没送过的情况
            if(a.isOnline != b.isOnline) {
                return a.isOnline?1:-1
            }
            if(a.quitTime != b.quitTime) {
                return b.quitTime - a.quitTime
            }
            return a.friendValue - b.friendValue;
        }
    });
    return result
}

function getSentHeart(roleId: string, relation: Relation) {
    let friendShip = <FriendShipType>relation.friendShip;
    let json = outputCnt(roleId, friendShip);
    if(!json) {
        return {
            beSentHeart: 0,
            beSentHeartTime: 0
        }
    }
    return {
        beSentHeart: json.beSentHeart,
        beSentHeartTime: json.beSentHeartTime
    }
}

export async function getFriendLvAdd(roleId: string, hisRoleId: string) {
    let friendShip = await FriendShipModel.getFriendLv(roleId, hisRoleId);
    if(!friendShip) {
        return 0
    }
    let dic = gameData.roleFriendLv.get(friendShip.friendLv);
    if(!dic) {
        return 0
    }
    return dic.comBattleAdd
}