import { UserModel } from '@db/User';
import { RoleModel } from '@db/Role';
import { HeroModel } from '@db/Hero';
import { EquipModel } from '@db/Equip';
import { ActionPointModel } from '@db/ActionPoint';
import { BattleDropModel } from '@db/BattleDrop';
import { BattleRecordModel } from '@db/BattleRecord';
import { BattleSweepRecordModel } from '@db/BattleSweepRecord';
import { DailyRecordModel } from '@db/DailyRecord';
import { EventRecordModel } from '@db/EventRecord';
import { ExpeditionPointModel } from '@db/ExpeditionPoint';
import { ExpeditionRecordModel } from '@db/ExpeditionRecord';
import { ExpeditionWarRecordModel } from '@db/ExpeditionWarRecord';
import { HangUpRecordModel } from '@db/HangUpRecord';
import { HangUpSpdUpRecModel } from '@db/HangUpSpdUpRec';
import { SearchRecordModel } from '@db/SearchRecord';
import { TowerRecordModel } from '@db/TowerRecord';
import { TowerTaskRecModel } from '@db/TowerTaskRec';
import { PvpDefenseModel } from '@db/PvpDefense';

import { Service } from 'egg';
import Counter from '@db/Counter';
import { STATUS, HERO_SYSTEM_TYPE } from '@consts';
import { ITID, COUNTER } from '@consts';
import { ItemModel } from '@db/Item';
import { gameData, getHeroExpByLv, getExpByLv } from '@pubUtils/data';
import { calPlayerCeAndSave, calculatetopLineup, calEquipSeids } from '@pubUtils/playerCe';
import { SchoolModel } from '@db/School';
import { Attribute } from '@domain/roleField/attribute';
import { smsModel } from '@db/Sms';
import { isString } from 'underscore';
import { FriendShipModel } from '@db/FriendShip';
import { FriendApplyModel } from '@db/FriendApply';
import { FriendRelationModel } from '@db/FriendRelation';
import { createHero as pubCreateHero, addSkin } from '@pubUtils/itemUtils';

/**
 * Test Service
 */
export default class GMUsers extends Service {

    /**
     * 根据类型等搜索玩家
     */
    public async getuserlist(field: string = 'all', value: string = '') {
        const { ctx } = this;

        let arr = new Array(), flag = 0;
        if (value == '') field = 'all';
        let valueArr = value.split(',');
        for (let i of valueArr) {
            if (field == 'uid') {
                let d = parseInt(i);
                if (isNaN(d)) {
                    flag = 1; break;
                } else {
                    arr.push(d);
                }
            } else if (field == 'username' || field == 'tel') {
                arr.push(i);
            } else if (field == 'all') {
                break;
            } else {
                flag = 1; break;
            }
        }

        if (flag) {
            return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        }

        let users = await UserModel.findUserByField(field, valueArr);

        if (users) {
            let list = new Array();
            for (let user of users) {
                let role = await RoleModel.findAllByUid(user.uid);
                let sms = await smsModel.findByTel(user.tel);

                list.push({ ...user, role, isFixed: sms ? sms.isFixed : false, code: sms ? sms.code : "" });
            }

            return ctx.service.utils.resResult(STATUS.SUCCESS, { list })
        } else {
            console.error('userlist not found');
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR);
        }
    }

    public async createRole(uid: number, serverId: number, roleName: string) {
        console.log('enter Auth createRole');
        const ctx = this.ctx;

        const roleId = ctx.service.utils.genCode(10);
        const code = ctx.service.utils.genCode(6);
        const seqId = await Counter.getNewCounter(COUNTER.ROLE) || -1;
        const role = await RoleModel.createRole(uid, serverId, { roleId, code, roleName, seqId });
        if (role) {
            return ctx.service.utils.resResult(STATUS.SUCCESS);
        } else {
            console.error('create role error');
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR);
        }
    }

    public async addAuth(uid: number, auth: number) {
        console.log('enter Auth addAuth');
        const ctx = this.ctx;

        const user = await UserModel.addAuth(uid, auth);
        if (user) {
            return ctx.service.utils.resResult(STATUS.SUCCESS);
        } else {
            console.error('add auth error');
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR);
        }
    }

    public checkTelNo(telNo: string) {
        if (!isString(telNo)) {
            return { status: 1, data: '参数类型错误' };
        }
        if (telNo.length !== 11) {
            return { status: 1, data: '手机号长度错误' };
        }
        return { status: 0, data: '手机号合法' };
    }

    public async fixSms(tel: string) {
        console.log('enter Auth fix sms');
        const ctx = this.ctx;
        const checkTel = this.checkTelNo(tel);
        if (checkTel.status == 1) {
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR, checkTel.data);
        }
        const sms = await smsModel.fixSms(tel);
        if (sms) {
            return ctx.service.utils.resResult(STATUS.SUCCESS);
        } else {
            console.error('fix sms error');
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR);
        }
    }

    public async deleteRole(roleId: string) {
        console.log('enter Auth deleteRole');
        const ctx = this.ctx;
        await ActionPointModel.deleteAccount(roleId);
        await BattleDropModel.deleteAccount(roleId);
        await BattleRecordModel.deleteAccount(roleId);
        await BattleSweepRecordModel.deleteAccount(roleId);
        await DailyRecordModel.deleteAccount(roleId);
        await EquipModel.deleteAccount(roleId);
        await EventRecordModel.deleteAccount(roleId);
        await ExpeditionPointModel.deleteAccount(roleId);
        await ExpeditionRecordModel.deleteAccount(roleId);
        await ExpeditionWarRecordModel.deleteAccount(roleId);
        await HangUpSpdUpRecModel.deleteAccount(roleId);
        await HangUpRecordModel.deleteAccount(roleId);
        await HeroModel.deleteAccount(roleId);
        await RoleModel.deleteAccount(roleId);
        await SearchRecordModel.deleteAccount(roleId);
        await TowerTaskRecModel.deleteAccount(roleId);
        await TowerRecordModel.deleteAccount(roleId);
        await PvpDefenseModel.deleteAccount(roleId);
        await ItemModel.deleteAccount(roleId);
        await SchoolModel.deleteAccount(roleId);
        await FriendShipModel.deleteAccount(roleId);
        await FriendApplyModel.deleteAccount(roleId);
        await FriendRelationModel.deleteAccount(roleId);

        return ctx.service.utils.resResult(STATUS.SUCCESS);
    }



    /**
     * 根据类型等搜索玩家
     */
    public async getrolelist(field: string = 'all', value: string = '') {
        const { ctx } = this;

        let arr = new Array(), flag = 0;
        let valueArr = value.split(',');
        if (value == '') field = 'all';
        for (let i of valueArr) {
            if (field == 'uid') {
                let d = parseInt(i);
                if (isNaN(d)) {
                    flag = 1; break;
                } else {
                    arr.push(d);
                }
                field = 'userInfo.uid';
            } else if (field == 'roleName') {
                arr.push(i);
            } else if (field == 'tel') {
                arr.push(i);
                field = 'userInfo.tel';
            } else if (field == 'all') {
                break;
            } else {
                flag = 1; break;
            }
        }

        if (flag) {
            return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        }

        let roles = await RoleModel.findRoleByField(field, valueArr);

        if (roles) {

            let result = new Array();
            for (let role of roles) {
                let heroCount = await HeroModel.count({ roleId: role.roleId }).lean();
                let equipCount = await EquipModel.count({ roleId: role.roleId }).lean();
                let itemCount = await ItemModel.count({ roleId: role.roleId }).lean();
                let defense = await PvpDefenseModel.findByRoleId(role.roleId);

                let { roleId, roleName, serverId, lv, vLv, gold, coin } = role;
                let { uid, tel } = role.userInfo;
                result.push({
                    key: roleId, roleId, roleName, serverId, lv, vLv, uid, tel, heroCount, equipCount, itemCount, gold, coin,
                    hasDefense: defense ? '是' : '否', defCe: defense ? defense.defCe : 0
                });
            }
            return ctx.service.utils.resResult(STATUS.SUCCESS, { list: result });
        } else {
            console.error('role list not found');
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR);
        }
    }

    public async createHero(uids: Array<string>, _hid: string, _hlv: string) {
        const { ctx } = this;
        console.log('gm createHero', uids, _hid, _hlv);
        let hlv = parseInt(_hlv);
        if (isNaN(hlv)) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        let hids = (_hid as string).split('&').map(cur => parseInt(cur));
        for (let hid of hids) {
            if (isNaN(hid)) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        }

        let heroInfos = new Array();
        for (let roleId of uids) {
            let role = await RoleModel.findByRoleId(roleId);
            if (role) {
                for (let hid of hids) {
                    let hero = await HeroModel.findByHidAndRole(hid, roleId);
                    if (hero) continue;
                    let dicHero = gameData.hero.get(hid);
                    if (!dicHero) continue;
                    const heroInfo = {
                        roleId, roleName: role.roleName, hid, serverId: role.serverId,
                        lv: hlv, exp: getHeroExpByLv(hlv - 1) || 0
                    }
                    heroInfos.push(heroInfo);
                }
            } else {
                return ctx.service.utils.resResult(STATUS.GM_CREATE_ERROR, null, '未找到角色' + roleId)
            }
        }

        try {
            for (let heroInfo of heroInfos) {
                await pubCreateHero(heroInfo.roleId, heroInfo.roleName, heroInfo.serverId, heroInfo);
            }
            return ctx.service.utils.resResult(STATUS.SUCCESS, { uids });
        } catch (e) {
            console.error(e.stack)
            return ctx.service.utils.resResult(STATUS.GM_CREATE_ERROR, null, e.stack);
        }
    }

    public async createEquip(uids: Array<string>, _eid: string, _ecount: string, _ehid: string) {
        const { ctx } = this;
        console.log('gm createEquip', uids, _eid, _ecount, _ehid);
        let eids = (_eid as string).split('&').map(cur => parseInt(cur));
        let ecount = parseInt(_ecount);
        let ehid = parseInt(_ehid);
        if (isNaN(ecount) || isNaN(ehid)) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        for (let eid of eids) {
            if (isNaN(eid)) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        }
        let flag = 0, msg = '创建失败';
        for (let roleId of uids) {
            let role = await RoleModel.findByRoleId(roleId);
            if (role) {
                for (let eid of eids) {
                    for (let i = 0; i < ecount; i++) {

                        let dicEquip = gameData.goods.get(eid);
                        if (!dicEquip) {
                            flag = 1, msg = "未找到装备" + eid;
                            break;
                        }
                        await ctx.service.utils.addEquips(roleId, role.roleName, { id: eid, ...dicEquip, hid: ehid });
                    }
                }
            } else {
                flag = 1, msg = '未找到角色' + roleId;
            }
        }

        if (flag) {
            return ctx.service.utils.resResult(STATUS.GM_CREATE_ERROR, null, msg);
        } else {
            return ctx.service.utils.resResult(STATUS.SUCCESS, { uids });
        }
    }

    public async createItem(uids: Array<string>, _itemid: string, _itemcount: string) {
        const { ctx } = this;
        console.log('gm createItem', uids, _itemid, _itemcount);
        let itemids = (_itemid as string).split('&').map(cur => parseInt(cur));
        for (let itemid of itemids) {
            if (isNaN(itemid)) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        }
        let itemcount = parseInt(_itemcount);
        if (isNaN(itemcount)) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);

        let flag = 0, msg = '创建失败';
        for (let itemid of itemids) {
            let dicGoods = gameData.goods.get(itemid);
            let itidObj = ITID.get(dicGoods.itid);

            if (!dicGoods) {
                flag = 1, msg = "未找到道具" + itemid;
            } else if (!itidObj) {
                flag = 1, msg = "未找到道具" + itemid;
            } else {
                for (let roleId of uids) {
                    let role = await RoleModel.findByRoleId(roleId);
                    if (role) {
                        await ctx.service.utils.addBags(roleId, role.roleName, { id: itemid, itemName: dicGoods.name, count: itemcount, type: itidObj.type, hid: 0 });
                    } else {
                        flag = 1, msg = '未找到角色' + roleId;
                    }
                }
            }
        }

        if (flag) {
            return ctx.service.utils.resResult(STATUS.GM_CREATE_ERROR, null, msg);
        } else {
            return ctx.service.utils.resResult(STATUS.SUCCESS, { uids });
        }
    }

    public async addGold(uids: Array<string>, _count: string) {
        const { ctx } = this;
        console.log('gm addGold', uids, _count);
        let count = parseInt(_count);
        if (isNaN(count)) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        for (let roleId of uids) {
            await RoleModel.addGoldFree(roleId, count);
        }

        return ctx.service.utils.resResult(STATUS.SUCCESS, { uids });
    }

    public async addCoin(uids: Array<string>, _count: string) {
        const { ctx } = this;
        console.log('gm addCoin', uids, _count);
        let count = parseInt(_count);
        if (isNaN(count)) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        for (let roleId of uids) {
            await RoleModel.addCoin(roleId, count);
        }

        return ctx.service.utils.resResult(STATUS.SUCCESS, { uids });
    }
    public async addSkin(uids: Array<string>, _id: string) {
        const { ctx } = this;
        console.log('gm addSkin', uids, _id);
        let id = parseInt(_id);
        if (isNaN(id)) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        for (let roleId of uids) {
            let role = await RoleModel.findByRoleId(roleId);
            await addSkin(roleId, role.roleName, id, false);
        }

        return ctx.service.utils.resResult(STATUS.SUCCESS, { uids });
    }

    public async levelUp(uids: Array<string>, _lv: string) {
        const { ctx } = this;
        console.log('gm levelUp', uids, _lv);
        let lv = parseInt(_lv);
        if (isNaN(lv)) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        for (let roleId of uids) {
            let exp = getExpByLv(lv - 1);
            await RoleModel.levelup(roleId, lv, exp ? exp.sum : 0);
        }

        return ctx.service.utils.resResult(STATUS.SUCCESS, { uids });
    }

    public async getPvpDefense(roleId: string) {
        const { ctx } = this;
        let result = await PvpDefenseModel.findByRoleId(roleId);
        return ctx.service.utils.resResult(STATUS.SUCCESS, {
            hasDefense: !!result, defense: result
        })
    }

    //   public async getHeroList(roleId: string) {
    //     const {ctx} = this;
    //     let herolist = await HeroModel.findByRole(roleId);
    //     let defense = await PvpDefenseModel.findByRoleId(roleId);

    //     let result = Array<Hero>();
    //     for(let hero of herolist) {
    //         if(defense) {
    //             let {heroes = []} = defense;
    //             let curHero = heroes.find(cur => cur.actorId == hero.hid);
    //             if(!curHero) {
    //                 result.push(hero);
    //             }
    //         } else{
    //             result.push(hero);
    //         }
    //     }

    //     return ctx.service.utils.resResult(STATUS.SUCCESS, {
    //         heroes: result
    //     })
    //   }

    public async saveHeroToDefense(roleId: string, _roleName: string, hid: number) {
        const { ctx } = this;
        let hero = await HeroModel.findByHidAndRole(hid, roleId);
        let role = await RoleModel.findByRoleId(roleId);
        if (!hero || !role) {
            return ctx.service.utils.resResult(STATUS.GM_HERO_NOT_FOUND);
        }
        let { lv, ce, attr: heroAttrs } = hero;
        let { attr: roleAttrs } = role;


        let dicHero = gameData.hero.get(hid);

        let attribute = new Attribute();
        attribute.setByDbData(roleAttrs, heroAttrs);

        let heroInfo = {
            actorId: dicHero.heroId,
            actorName: dicHero.name,
            attribute, lv,
            ce
        };

        let defense = await PvpDefenseModel.findByRoleId(roleId);
        if (!defense) {
            // defense = await PvpDefenseModel.createPvpDefense({roleId, roleName, heroes: [], defCe:ce});
        } else {
            defense = await PvpDefenseModel.addHeroToDefense(roleId, heroInfo, ce);
        }
        return ctx.service.utils.resResult(STATUS.SUCCESS, {
            defense
        });
    }


    public async removeHeroFromDefense(roleId: string, hid: number) {
        const { ctx } = this;

        let defense = await PvpDefenseModel.findByRoleId(roleId);
        if (!defense) {
            return ctx.service.utils.resResult(STATUS.GM_PVP_DEFENSE_NOT_FOUND);
        }
        let { heroes } = defense;
        let curHero = heroes.find(cur => cur.actorId == hid);
        if (!curHero) {
            return ctx.service.utils.resResult(STATUS.GM_PVP_DEFENSE_HERO_NOT_FOUND);
        }
        defense = await PvpDefenseModel.removeHeroFromDefense(roleId, hid, curHero.ce);

        return ctx.service.utils.resResult(STATUS.SUCCESS, {
            defense
        });
    }

    /**
     * 根据类型等搜索玩家
     */
    public async getHeroList(field: string, value: (string | number)) {
        const { ctx } = this;

        let heroes = await HeroModel.findByField(field, value);

        if (heroes) {

            return ctx.service.utils.resResult(STATUS.SUCCESS, { list: heroes });
        } else {
            console.error('role list not found');
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR);
        }
    }


    public async deleteHero(roleIdAndHids: string[]) {
        console.log('enter Auth deleteRole');
        const ctx = this.ctx;
        for (let roleIdAndHid of roleIdAndHids) {
            let [roleId, hidStr] = roleIdAndHid.split('|');
            if (isNaN(parseInt(hidStr))) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);

            let hid = parseInt(hidStr);

            let hero = await HeroModel.findByHidAndRole(hid, roleId);
            if (!hero) continue;
            await HeroModel.deleteHero(roleId, hid);
            let role = await RoleModel.findByRoleId(roleId);
            await calculatetopLineup(role, hid, 0, null);
            await PvpDefenseModel.deleteHero(roleId, hid);
            await RoleModel.updateRoleInfo(roleId, { topLineup: role.topLineup, topLineupCe: role.topLineupCe, ce: role.ce - hero.ce });
        }

        return ctx.service.utils.resResult(STATUS.SUCCESS);
    }

    public async deleteEquip(roleIdAndSeqIds: string[]) {
        console.log('enter Auth deleteEquip');
        const ctx = this.ctx;
        let seqIds = new Array<number>();
        for (let roleIdAndSeqId of roleIdAndSeqIds) {
            let [roleId, seqIdStr] = roleIdAndSeqId.split('|');
            if (isNaN(parseInt(seqIdStr))) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);

            let seqId = parseInt(seqIdStr);
            console.log(seqId);
            let equip = await EquipModel.findbySeqId(seqId);
            if (equip.hid > 0) {
                let hero = await HeroModel.findByHidAndRole(equip.hid, roleId);
                let index = hero.ePlace.findIndex(cur => cur.id == equip.ePlaceId);
                if (index < 0) continue;
                let args = calEquipSeids(hero);
                hero.ePlace[index].equip = null;
                await calPlayerCeAndSave(HERO_SYSTEM_TYPE.EQUIP, roleId, hero, {}, args);
            }
            seqIds.push(seqId);
        }
        await EquipModel.deleteEquips(seqIds);

        return ctx.service.utils.resResult(STATUS.SUCCESS);
    }

    public async deleteItem(roleIdAndIds: string[]) {
        console.log('enter Auth deleteItem');
        const ctx = this.ctx;
        let map = new Map<string, number[]>();
        for (let roleIdAndId of roleIdAndIds) {
            let [roleId, idStr] = roleIdAndId.split('|');
            if (isNaN(parseInt(idStr))) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);

            let id = parseInt(idStr);
            let cur = map.get(roleId);
            if (!cur) {
                cur = new Array<number>();
                map.set(roleId, cur);
            }
            cur.push(id);
        }

        for (let [roleId, ids] of map) {
            await ItemModel.deletebyRoleAndIds(roleId, ids);
        }

        return ctx.service.utils.resResult(STATUS.SUCCESS);
    }


    public async setItemCount(roleIdAndIds: string[], count: number) {
        console.log('enter Auth setItemCount');
        const ctx = this.ctx;
        let map = new Map<string, number[]>();
        for (let roleIdAndId of roleIdAndIds) {
            let [roleId, idStr] = roleIdAndId.split('|');
            if (isNaN(parseInt(idStr))) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);

            let id = parseInt(idStr);
            let cur = map.get(roleId);
            if (!cur) {
                cur = new Array<number>();
                map.set(roleId, cur);
            }
            cur.push(id);
        }

        for (let [roleId, ids] of map) {
            await ItemModel.updateCountByRoleAndIds(roleId, ids, count);
        }

        return ctx.service.utils.resResult(STATUS.SUCCESS);
    }

    public async setHeroLv(roleIdAndHids: string[], _hlv: string) {

        try {
            console.log('gm setHeroLv', roleIdAndHids, _hlv);
            const ctx = this.ctx;
            let hlv = parseInt(_hlv);
            if (isNaN(hlv)) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);

            for (let roleIdAndHid of roleIdAndHids) {
                let [roleId, hidStr] = roleIdAndHid.split('|');
                if (isNaN(parseInt(hidStr))) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);

                let hid = parseInt(hidStr);

                let hero = await HeroModel.findByHidAndRole(hid, roleId);
                console.log(hid, roleId, !!hero);
                if (!hero) continue;
                await calPlayerCeAndSave(HERO_SYSTEM_TYPE.LVUP, roleId, hero, { lv: hlv });
            }

            return ctx.service.utils.resResult(STATUS.SUCCESS);
        } catch (e) {
            console.error(e.stack)
        }
    }

    /**
     * 根据类型等搜索装备
     */
    public async getEquipList(field: string, value: (string | number)) {
        const { ctx } = this;

        let equips = await EquipModel.findByField(field, value);

        if (equips) {

            return ctx.service.utils.resResult(STATUS.SUCCESS, { list: equips });
        } else {
            console.error('role list not found');
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR);
        }
    }


    /**
     * 根据类型等搜索道具
     */
    public async getItemList(field: string, value: (string | number)) {
        const { ctx } = this;

        let items = await ItemModel.findByField(field, value);

        if (items) {

            return ctx.service.utils.resResult(STATUS.SUCCESS, { list: items });
        } else {
            console.error('role list not found');
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR);
        }
    }
}
