import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, mongoose, Ref } from '@typegoose/typegoose';
import Role, { RoleType } from './Role';
import FriendShip, { FriendShipType } from './FriendShip';
import { ROLE_SELECT, POPULATE_TYPE } from '../consts';

export class Relation {
    @prop({ required: true, default: '' })
    roleId: string;     // 对方玩家id
    @prop({ required: true, ref: 'Role', type: mongoose.Schema.Types.ObjectId })
    role: Ref<Role>;
    @prop({ required: true, ref: 'FriendRelation', type: mongoose.Schema.Types.ObjectId })
    friendShip: Ref<FriendShip>;
}

/**
  * 好友系统关系表
  */
@index({ roleId: 1, createdAt: -1 })

export default class FriendRelation extends BaseModel {
    @prop({ required: true, default: '' })
    roleId: string;	    // 操作玩家本人id

    @prop({ required: true, default: [], type: Relation, _id: false })
    friends: Relation[]; // 好友列表
    @prop({ required: true, default: [], type: Relation, _id: false })
    blacklist: Relation[]; // 黑名单列表

    // 创建
    public static async addFriend(roleId: string, friend: RoleType, friendShip: FriendShipType) {

        const result: FriendRelationType = await FriendRelationModel.findOneAndUpdate(
            { roleId }, {
            $setOnInsert: { blacklist: [] },
            $push: { friends: { roleId: friend.roleId, role: friend._id, friendShip: friendShip._id } }
        }, { upsert: true, new: true }).lean();

        return result;
    }


    // 获取列表
    public static async findFriendByRole(roleId: string, populateType: number) {
        let document = FriendRelationModel.findOne({ roleId })
            .lean({ getters: true, virtuals: true });

        if (populateType == POPULATE_TYPE.FRIEND) {
            document
                .populate('friends.role', ROLE_SELECT.SHOW_SIMPLE, 'Role')
                .populate('friends.friendShip', null, 'FriendShip');
        } else if (populateType == POPULATE_TYPE.BLACKLIST) {
            document
                .populate('blacklist.role', ROLE_SELECT.SHOW_SIMPLE, 'Role')
        } else if (populateType == POPULATE_TYPE.FRIENDSHIP) {
            document.populate('friends.friendShip', null, 'FriendShip');
        } else if (populateType == POPULATE_TYPE.FRIEND_NAME_ONLY) {
            document
                .populate('friends.role', 'roleName', 'Role')
        }

        let result: FriendRelationType = await document.lean({ getters: true, virtuals: true });;

        // console.log(JSON.stringify(result));
        return result;
    }

    public static async moveFromFriend(roleId: string, friend: RoleType, friendShip: FriendShipType, toBlack: boolean, hasFriend: boolean ) {
        let update = {}
        let setOnInsert = {};
        if(hasFriend) {
            update['$pull'] = { friends: { roleId: friend.roleId } };
        } else {
            setOnInsert['friends'] = [];
        }
        if(toBlack) {
            update['$push'] = { blacklist: { roleId: friend.roleId, role: friend._id, friendShip: friendShip? friendShip._id: null } };
        } else {
            setOnInsert['blacklist'] = [];
        }
        update['$setOnInsert'] = setOnInsert;

        let result: FriendRelationType = await FriendRelationModel.findOneAndUpdate({ roleId }, update, { upsert: true, new: true });
        return result
    }

    public static async removeFromBlack(roleId: string, frdRoleId: string ) {
        let result: FriendRelationType = await FriendRelationModel.findOneAndUpdate({ roleId }, {
            $pull: { blacklist: { roleId: frdRoleId } },
            $setOnInsert: { friends: [] }
        }, { upsert: true, new: true });
        return result
    }

    public static async isInBlackList(roleId: string, hisRoleId: string) {
        let result = await FriendRelationModel.find({
            $or: [{ roleId, 'blacklist.roleId': hisRoleId}, { hisRoleId, 'blacklist.roleId': roleId}]
        }).lean();
        return result.length > 0;
    }

    public static async updateInfo(roleId: string, update: friendShipUpdate) {
        const result = await FriendRelationModel.findOneAndUpdate({ roleId }, {$set: update}, { new: true }).lean();
        return result;
    }

    public static async deleteAccount(roleId: string) {
        let result = await FriendRelationModel.deleteMany({ roleId });
        await FriendRelationModel.updateMany({}, { $pull: { friends: { roleId }, blacklist: { roleId } }});
        return result;
    }
}

export const FriendRelationModel = getModelForClass(FriendRelation);

export interface FriendRelationType extends Pick<DocumentType<FriendRelation>, keyof FriendRelation> { };
type friendShipUpdate = Partial<FriendRelationType>; // 将所有字段变成可选项