import CryptoJS from 'crypto-js';
import {ObjectId, OptionalId, WithId} from 'mongodb';
import {BaseConnection} from 'tsrpc';
import {Wjjl} from '../module/collection_wjjl';
import {ServiceType} from '../shared/protocols/serviceProto';
import {ReqLogin, ResLogin, playerAppend, playerAttr, playerInfo} from '../shared/protocols/user/PtlLogin';
import {player} from '../shared/protocols/user/type';
import {PublicShared} from '../shared/public/public';
import {PlayerFun} from './player';
import {ZhanLingTasks} from './zhanling';
import {getGud, setGud} from './gud';

export const defaultUserInfo: playerInfo = {
    lv: 1,
    vip: 0,
    uid: '',
    bindUid: '',
    power: 0
};

export const defaultUserAttr: playerAttr = {
    nexp: 0,
    jinbi: 100,
    rmbmoney: 100,
    rongyu: 0,
    payExp: 0,
    guijinshu: 0
};

export const defaultUserAppend: playerAppend = {
    name: '',
    tujianLv: 0,
    head: {id: "1", time: -1},
    headFrame: {id: "1", time: -1},
    chatFrame: {id: "1", time: -1},
    upModel: {id: "1", time: -1},
    model: {
        1: {id: "1", time: -1},
        2: {id: "2", time: -1}
    },
    renown: 0,
    wxcLv: {
        lv: 0,
        ids: []
    },
    mapId: 0,
    shoucangping: {},
    useTujianLvPoint: 0,
    skills: {},
    fightSkills: {},
    heroPos: {
        1: '',
        2: '',
        3: '',
        4: '',
        5: '',
        6: ''
    },
    ghId: '',
    ghName: '',
    ghLevel: 0,
    ghwz: {1: 0, 2: 0, 3: 0, 4: 0}
};

export class UserFun {
    static create(bUid: string) {
        let {bindUid, ...userInfo} = defaultUserInfo;

        return {
            bindUid: bUid,
            ...userInfo,
            ...defaultUserAttr
        };
    }

    static async check(gud: ResLogin['gud'], req: ReqLogin) {
        let obj: k_v<any> = {};
        let add: k_v<any> = {};
        for (let k in defaultUserAppend) {
            if (gud[k] == undefined) {
                let val = defaultUserAppend[k];
                switch (k as keyof playerAppend) {
                    // case 'name':
                    //     let b64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(gud.bindUid + gud.sid));
                    //     val = `temp_${b64}`.toLocaleLowerCase();
                    //     break;
                }
                gud[k] = val;
                add[k] = val;
            }
        }

        for (let k in G.gc.attr) {
            if (gud[k] == undefined) {
                gud[k] = defaultUserAttr[k];
                add[k] = defaultUserAttr[k] || 0;
            }
        }

        if (!gud.cTime) {
            gud.cTime = G.time;
            add.cTime = G.time;
        }

        if (!gud.sid) {
            gud.sid = req.sid;
            add.sid = req.sid;
        }

        if (!gud.serverName) {
            gud.serverName = req.serverName;
            add.serverName = req.serverName;
        }

        if (!gud.matrix) {
            gud.matrix = Object.fromEntries(Object.keys(G.gc.fightPlan).map(t => [t, 0]));
            gud.selectMatrix = '';

            add.matrix = gud.matrix;
            add.selectMatrix = gud.selectMatrix;
        }

        if (!gud.fightHeros) {
            let h_ids = Object.values(gud.heroPos).filter(_id => _id != '');

            if (h_ids.length < 1) {
                gud.fightHeros = [];
            } else {
                let dHeros = await G.mongodb.collection('hero').find({_id: {$in: h_ids.map(id => G.mongodb.conversionId(id))}}).toArray();
                gud.fightHeros = dHeros.map(h => h.heroId.toString());
            }
            add.fightHeros = gud.fightHeros;
        }

        if (!gud.matrixPos) {
            gud.matrixPos = Object.fromEntries(Object.keys(G.gc.fightPlan).map(pos => [pos, {...gud.heroPos}]));
            add.matrixPos = gud.matrixPos;
        }

        if (!gud.helpHeros) {
            gud.helpHeros = [];
            add.helpHeros = [];
        }

        if (!gud.headFrames) {
            gud.headFrames = {};
            for (let [id, conf] of Object.entries(G.gc.playerHeadFrame)) {
                if (typeof gud[conf.cond[0]] == 'number' && gud[conf.cond[0]] >= conf.cond[1]) {
                    gud.headFrames[id] = -1;
                } else {
                    switch (conf.cond[0]) {
                        case 'wxcLv':
                            if (gud.wxcLv.lv >= conf.cond[1]) gud.headFrames[id] = -1;
                            break;
                    }
                }

            }
            add.headFrames = gud.headFrames;
        }

        if (!gud.chatFrames) {
            gud.chatFrames = {};
            for (let [id, conf] of Object.entries(G.gc.playerChatFrame)) {
                if (typeof gud[conf.cond[0]] == 'number' && gud[conf.cond[0]] >= conf.cond[1]) {
                    gud.chatFrames[id] = -1;
                } else {
                    switch (conf.cond[0]) {
                        case 'wxcLv':
                            if (gud.wxcLv.lv >= conf.cond[1]) gud.chatFrames[id] = -1;
                            break;
                    }
                }
            }
            add.chatFrames = gud.chatFrames;
        }

        if (gud.onlineTime == undefined) {
            gud.onlineTime = 0;
            add.onlineTime = 0;
        }

        //每天首次登陆
        if (!gud.loginTime || PublicShared.getToDayZeroTime(gud.loginTime) != PublicShared.getToDayZeroTime(G.time)) {
            gud.loginDays = gud.loginDays ? gud.loginDays + 1 : 1;
            add.loginDays = gud.loginDays;
            Wjjl.setVal(gud.uid, `toDayLogin_${PublicShared.getOpenServerDay(gud.cTime, G.time)}`, 1);

            if (gud.logoutTime && PublicShared.getToWeekMondayZeroTime(gud.logoutTime) < PublicShared.getToWeekMondayZeroTime(G.time)) {
                ZhanLingTasks.clearLog(gud.uid, 'week');
            }

            obj.todayFirstLogin = true;
        }

        gud.loginTime = G.time;
        add.loginTime = G.time;

        if (Object.keys(add).length > 0) {
            G.mongodb.collection('user').updateOne({bindUid: gud.bindUid, sid: gud.sid}, {
                $set: {
                    ...add
                }
            });
            setGud(gud.uid, add);
        }

        return obj;
    }

    // 检查空数据并修复
    static async checkUidOrName() {
        let users = await G.mongodb.collection('user').findOne({$or: [{uid: {$in: ['', null]}}, {name: {$in: ['', null]}}]})
        if (users) {
            let {bindUid, sid, _id} = users
            let uid = users.uid || (sid + '_' + _id)
            // 随机创建name
            let b64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(bindUid + sid));
            let name = users.name || `temp_${b64}`.toLocaleLowerCase();
            await G.mongodb.collection('user').updateOne({bindUid, sid}, {
                $set: {
                    uid, name
                }
            });
        }
        return
    }

    /**创建账号数据 */
    static async createUser(client: BaseConnection<ServiceType>, bindUid: string, sid: number): Promise<WithId<OptionalId<ResLogin['gud']>>> {
        // 开启事务
        // let session = G.mongodbClient.startSession()
        // session.startTransaction() // 开启事务
        let gud: ResLogin['gud'] = this.create(bindUid);
        gud.sid = sid
        gud._id = new ObjectId()
        gud.uid = sid + '_' + gud._id.toHexString();
        // 随机创建name
        let b64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(gud.bindUid + gud.sid));
        gud.name = `temp_${b64}`.toLocaleLowerCase();
        gud.logoutTime = 0 // 设置默认值
        gud.status = 0 // 设置默认值
        gud.status_chat = 0 // 设置默认值

        await G.mongodb.collection('user').insertOne(gud);
        // await G.mongodb.collection('user').updateOne({ bindUid,sid }, {
        //     $set: {
        //         uid: gud.uid,
        //         name: gud.name
        //     }
        // });
        // 暂不做错误预处理，提交事务
        // session.abortTransaction() // 回滚
        // session.commitTransaction() // 提交
        // session.endSession() // 结束事务
        return gud as WithId<OptionalId<ResLogin['gud']>>;
    }

    /**获取玩家附带的buff加成 */
    static getOtherBuff(gud: ResLogin['gud']) {
        return gud;
    }

    static async getGud(uid: string) {
        return await getGud(uid);
    }

    /**激活头像框 */
    static async activeHeadFrame(uid: string, k: string, v: number) {
        let gud: player;
        gud = await getGud(uid);

        let change = false;
        let headFrame = G.gc.playerHeadFrame;
        let checks = Object.values(headFrame).filter(v => v.cond[0] == k);
        if (checks.length > 0) {
            checks.forEach(conf => {
                let val = v;
                if (k == 'wxcLv') val = gud.wxcLv.lv;
                else if (gud[k] != undefined) val = gud[k];

                if (k == 'jjc_rank') {
                    if (!gud.headFrames[conf.id] && val <= conf.cond[1]) {
                        gud.headFrames[conf.id] = -1;
                        change = true;
                    } else return
                } else if (!gud.headFrames[conf.id] && val >= conf.cond[1]) {
                    gud.headFrames[conf.id] = -1;
                    change = true;
                }
            });
        } else {
            let conf = headFrame[k];
            if (conf?.cond?.[0] == 'time') {
                let val = conf.cond[1];

                if (val == -1 && !gud.headFrames[conf.id]) {
                    change = true;
                    gud.headFrames[conf.id] = -1;
                } else if (!gud.headFrames[conf.id] || gud.headFrames[conf.id] < G.time) {
                    change = true;
                    gud.headFrames[conf.id] = G.time + val * v;
                } else {
                    change = true;
                    gud.headFrames[conf.id] += val * v;
                }
            }
        }

        if (change) {
            PlayerFun.changeAttr(uid, {headFrames: gud.headFrames});
            G.server.sendMsgByUid(uid, 'msg_s2c/PlayerChange', {headFrames: gud.headFrames});
            G.server.uid_connections[uid]?.refreshPower();
        }
    }

    /**激活聊天框 */
    static async activeChatFrame(uid: string, k: string, v: number) {
        let gud: player;
        gud = await getGud(uid);

        let change = false;
        let chatFrame = G.gc.playerChatFrame;
        let checks = Object.values(chatFrame).filter(v => v.cond[0] == k);
        if (checks.length > 0) {
            checks.forEach(conf => {
                let val = v;
                if (k == 'wxcLv') val = gud.wxcLv.lv;
                else if (gud[k] != undefined) val = gud[k];

                if (k == 'jjc_rank' && !gud.chatFrames[conf.id] && val <= conf.cond[1]) {
                    gud.chatFrames[conf.id] = -1;
                    change = true;
                } else if (!gud.chatFrames[conf.id] && val >= conf.cond[1]) {
                    gud.chatFrames[conf.id] = -1;
                    change = true;
                }
            });
        } else {
            let conf = chatFrame[k];
            if (conf?.cond?.[0] == 'time') {
                let val = conf.cond[1];

                if (val == -1 && !gud.chatFrames[conf.id]) {
                    change = true;
                    gud.chatFrames[conf.id] = -1;
                } else if (!gud.chatFrames[conf.id] || gud.chatFrames[conf.id] < G.time) {
                    change = true;
                    gud.chatFrames[conf.id] = G.time + val * v;
                } else {
                    change = true;
                    gud.chatFrames[conf.id] += val * v;
                }
            }
        }

        if (change) {
            PlayerFun.changeAttr(uid, {chatFrames: gud.chatFrames});
            G.server.sendMsgByUid(uid, 'msg_s2c/PlayerChange', {chatFrames: gud.chatFrames});
            G.server.uid_connections[uid]?.refreshPower();
        }
    }

    /**激活造型 */
    static async activeModel(uid: string, k: string, v: number) {
        let gud: player;
        gud = await getGud(uid);

        let change = false;
        let model = G.gc.playerModel;
        let checks = Object.values(model).filter(v => v.cond[0] == k);
        if (checks.length > 0) {
            checks.forEach(conf => {
                let val = v;
                if (k == 'wxcLv') val = gud.wxcLv.lv;
                else if (gud[k] != undefined) val = gud[k];

                if (k == 'jjc_rank' && !gud.model[conf.id] && val <= conf.cond[1]) {
                    gud.model[conf.id] = {id: conf.id + '', time: -1};
                    change = true;
                } else if (!gud.model[conf.id] && val >= conf.cond[1]) {
                    gud.model[conf.id] = {id: conf.id + '', time: -1};
                    change = true;
                }
            });
        } else {
            let conf = model[k];
            if (conf?.cond?.[0] == 'time') {
                let val = conf.cond[1];

                if (val == -1) {
                    change = true;
                    gud.model[conf.id] = {id: conf.id + '', time: -1};
                } else if (gud.model[conf.id].time < G.time) {
                    change = true;
                    gud.model[conf.id] = {id: conf.id + '', time: G.time + val * v};
                } else {
                    change = true;
                    gud.model[conf.id] = {id: conf.id + '', time: gud.model[conf.id].time += val * v}
                }
            }
        }

        if (change) {
            PlayerFun.changeAttr(uid, {model: gud.model});
            G.server.sendMsgByUid(uid, 'msg_s2c/PlayerChange', {model: gud.model});
            G.server.uid_connections[uid]?.refreshPower();
        }
    }
}