
import { COUNTER, DEFAULT_LV, ADULT_AGE, GUEST_MAX_TIME, BLOCK_TYPE, DEBUG_MAGIC_WORD } from '@consts';
import { RoleModel, WarStar } from '@db/Role';
import { UserModel, UserType } from '@db/User';
import { STATUS, GET_SMS_TYPE, ADDICTION_PREVENTION_CODE } from '@consts';
import { smsModel } from '@db/Sms';
import { Service } from 'egg';
import Counter from '@db/Counter';
import { gameData, getExpByLv } from '../pubUtils/data';
import { isString } from 'underscore';
import { getAge, nowSeconds } from '../pubUtils/timeUtil';
import { isDevelopEnv, resResult } from '../pubUtils/util';
import { checkTeeanAgerTime } from '../pubUtils/authenticateUtil';
// import { authenticate } from '../pubUtils/httpUtil';
import { getChannelId, loginValidata } from '../pubUtils/sdkUtil';
import { LoginValidateData37 } from 'app/domain/sdk';
import { ServerlistModel } from '@db/Serverlist';
import { DicWar } from '../pubUtils/dictionary/DicWar';
import { RScriptRecordModel } from '@db/RScriptRecord';
import { deletRole } from '../pubUtils/roleUtil';

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

    /**
     * 设备免密登录
     * @param telNo - 用户手机号
     */

    public async deviceLogin(isGuest: boolean, token: string, deviceId: string, platform: string, pkgName: string, serverType: string, getuiCID: string) {
        const ctx = this.ctx;

        let oldUser = await UserModel.findUserByToken(token);

        if (!oldUser) {
            if (isGuest) {
                const tel = ctx.service.utils.genCode(10);
                const token = ctx.service.utils.generateStr(256);
                let lastGuest = await UserModel.getLastDeviceGuest(deviceId, token);
                if (lastGuest) {
                    let param = this.getReturnParam(lastGuest, lastGuest.deviceId);
                    return this.ctx.service.utils.resResult(STATUS.SUCCESS, {
                        canLogin: true, // 未设置密码等于未创建账号
                        ...param
                    });
                } else {

                    let user = await UserModel.createUser(isGuest, tel, token, platform, pkgName, serverType, deviceId, 0, ctx.clientIp);
                    if (getuiCID) {//更新个推cid
                        await UserModel.updateGetuiCID(tel, getuiCID);
                    }
                    if(user && user.userCode) {
                        ctx.service.utils.checkOnlineUser(user.userCode);
                    }
                    let param = this.getReturnParam(user, null);

                    return this.ctx.service.utils.resResult(STATUS.SUCCESS, {
                        canLogin: true,
                        ...param
                    });
                }

            } else {

                return this.ctx.service.utils.resResult(STATUS.SUCCESS, {
                    canLogin: false
                });
            }
        } else {
            const token = ctx.service.utils.generateStr(256);
            let user = await UserModel.updateToken(oldUser.tel, token, deviceId, ctx.clientIp);
            if (getuiCID) {//更新个推cid
                await UserModel.updateGetuiCID(user.tel, getuiCID);
            }
            if(user && user.userCode) {
                ctx.service.utils.checkOnlineUser(user.userCode);
            }
            let param = this.getReturnParam(user, oldUser.deviceId);

            let canLogin = true;
            if (!user.isGuest && !user.hasSetPw) canLogin = false;
            return this.ctx.service.utils.resResult(STATUS.SUCCESS, {
                canLogin, // 未设置密码等于未创建账号
                ...param
            });
        }

    }

    private getReturnParam(user: UserType, deviceId: string) {
        let age = getAge(user.birthday);
        let isAdult = age >= ADULT_AGE;
        let todayPlayTime = user.todayPlayTime;
        let type = checkTeeanAgerTime(isAdult, todayPlayTime);
        if ((user.isGuest || !user.hasAuthenticated) && user.guestTime > GUEST_MAX_TIME) {
            type = ADDICTION_PREVENTION_CODE.GUEST;
        }

        return {
            tel: user.tel,
            isGuest: !!user.isGuest,
            guestTime: user.guestTime,                   // 游客已体验时间
            hasAuthenticated: !!user.hasAuthenticated,   // 是否进行过实名认证
            isAdult,                                     // 是否已成年
            todayPlayTime,                               // 今天已游戏时长
            type,                                        // 防沉迷类型
            hasSetPw: user.hasSetPw,                     // 是否设置了密码
            token: user.token,                           // 用户token
            userCode: user.userCode,                      // 用户标识    
            deviceId
        }
    }

    public checkTelNo(telNo) {
        if (!isString(telNo)) {
            return { status: 1, resResult: resResult(STATUS.WRONG_PARMS) };
        }
        if (telNo.length !== 11) {
            return { status: 1, resResult: resResult(STATUS.TEL_LEN_ERR) };
        }
        return { status: 0 };
    }

    async sendSmsCodeByGuodu(tel, code) {
        const ctx = this.ctx;
        const url = `http://221.179.172.68:8000/QxtSms/QxtFirewall?OperID=bantu3&OperPass=c8XcTffG&DesMobile=${tel}&Content=${encodeURIComponent(`【同人游戏】验证码${code}，您正在登录赵云传，若非本人操作，请勿泄露`)}&Content_Code=1`;
        const result = await ctx.curl(url, {
            method: 'GET',
        });
        return result.data;
    }

    testLimit(sms, interval) {
        if (sms.updateTime.getTime() > Date.now() - interval) {
            return true;
        }
        return false;
    }

    /**
     * 用户获取手机验证码
     * @param telNo - 用户手机号
     */

    public async getSms(type: number, tel: string) {
        const ctx = this.ctx;

        const telVerify = this.checkTelNo(tel);
        if (telVerify.status !== 0) {
            return telVerify.resResult;
        }

        if (type == GET_SMS_TYPE.BIND) {
            let telUser = await UserModel.findUserByTel(tel);
            if (telUser && telUser.uid != ctx.uid) {
                return ctx.service.utils.resResult(STATUS.TEL_HAS_USED);
            }
        }

        const sms = await smsModel.findByTel(tel, false);
        if (sms) {
            if (await sms.timeLimit(10000)) {
                return this.ctx.service.utils.resResult(STATUS.SMS_IN_60S);
            }
            if (await sms.cntLimit(8)) {
                return this.ctx.service.utils.resResult(STATUS.SMS_CNT_LIMIT);
            }
        }

        let code = '';
        if (sms && (!sms.used || sms.isFixed)) {
            code = sms.code;
        } else {
            code = this.ctx.service.utils.generateNum(6);
        }

        const smsResult = await this.sendSmsCodeByGuodu(tel, code);
        console.log(smsResult);
        await smsModel.updateByTel(tel, code, false, new Date(), sms?.hasSendToday() ? sms.countToday + 1 : 1);

        let user = await UserModel.findUserByTel(tel);
        return this.ctx.service.utils.resResult(STATUS.SUCCESS, {
            hasAccount: !!user && !!user.hasSetPw
        });
    }

    /**
     * 用户获取到手机验证码之后发送验证登录请求
     * @param tel 登录手机号
     * @param code 登录验证码
     * @param platform 平台
     * @param pkgName 包名
     * @param serverType 服务器类型
     */
    public async smsLogin(tel: string, deviceId: string, code: string, platform: string, pkgName: string, serverType: string, getuiCID: string) {
        const ctx = this.ctx;
        // 参数检查
        const telVerify = this.checkTelNo(tel);
        if (telVerify.status !== 0) {
            return telVerify.resResult;
        }

        // ! 测试阶段允许客户端不传验证码，此时不做验证码验证，直接注册或登录账号
        // TODO 上线前改掉或仅保留在测试服
        if (code !== '') {
            if (!isString(code) || code.length !== 6) {
                return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
            }

            // 手机验证码核验
            const smsValid: boolean = await smsModel.validateSms(tel, code);
            if (!smsValid) {
                const sms = await smsModel.findByTel(tel);
                if (sms && sms.isFixed) { // 固定手机号登录
                    if (sms.code !== code) {
                        return ctx.service.utils.resResult(STATUS.SMS_INVALID);
                    }
                } else {
                    return ctx.service.utils.resResult(STATUS.SMS_INVALID);
                }
            }
        }

        // 用户注册登录
        const token = ctx.service.utils.generateStr(256);
        const {user, deviceId: oldDeviceId} = await UserModel.createOrUpdate(false, tel, token, platform, pkgName, serverType, deviceId, ctx.clientIp);
        if (getuiCID) {//更新个推cid
            await UserModel.updateGetuiCID(tel, getuiCID);
        }
        if(user && user.userCode) {
            ctx.service.utils.checkOnlineUser(user.userCode);
        }
        let param = this.getReturnParam(user, oldDeviceId);
        return ctx.service.utils.resResult(STATUS.SUCCESS, param);
    }


    /**
     * 给策划用于直接获得手机号验证码
     * @param tel 登录手机号
     */
    public async getSmsCode(tel: string) {
        const ctx = this.ctx;

        const sms = await smsModel.findByTel(tel);
        if (sms) {
            return ctx.service.utils.resResult(STATUS.SUCCESS, { code: sms?.code });
        } else {
            return ctx.service.utils.resResult(STATUS.SMS_INVALID);
        }
    }

    /**
     * 设置密码
     * @param password 密码
     */
    public async setPassword(password: string) {
        const { ctx } = this;
        const { uid } = ctx;
        if (!password) return ctx.service.utils.resResult(STATUS.PASSWORD_ILLEGEL);

        let user = await UserModel.setPass(uid, password);
        if (user) {
            let param = this.getReturnParam(user, user.deviceId);
            return ctx.service.utils.resResult(STATUS.SUCCESS, param);
        } else {
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR);
        }
    }

    /**
     * 密码登录
     * @param tel 登录手机号
     * @param code 登录验证码
     * @param platform 平台
     * @param pkgName 包名
     * @param serverType 服务器类型
     */
    public async pwLogin(tel: string, deviceId: string, pw: string, getuiCID: string) {
        const ctx = this.ctx;
        // 参数检查
        const telVerify = this.checkTelNo(tel);
        if (telVerify.status !== 0) {
            return telVerify.resResult;
        }


        // 用户注册登录
        const token = ctx.service.utils.generateStr(256);
        const {user, deviceId: oldDeviceId} = await UserModel.checkPass(tel, pw, token, deviceId);
        if (!user) return ctx.service.utils.resResult(STATUS.PASSWORD_ERR);
        if (getuiCID) {//更新个推cid
            await UserModel.updateGetuiCID(tel, getuiCID);
        }
        if(user && user.userCode) {
            ctx.service.utils.checkOnlineUser(user.userCode);
        }
        let param = this.getReturnParam(user, oldDeviceId);
        return ctx.service.utils.resResult(STATUS.SUCCESS, { ...param });
    }

    public async checkRole(serverId: number) {
        const ctx = this.ctx;
        const { uid } = ctx;
        let canLogin = await this.ctx.service.utils.validateCanLogin();
        if(!canLogin) return this.ctx.service.utils.resResult(STATUS.ONLINE_USER_MAX);

        const role = await RoleModel.findByUid(uid, serverId);
        if (role) {
            if(role.blockType == BLOCK_TYPE.BLOCK) {
                return ctx.service.utils.resResult(STATUS.BLOCKED);
            }
            return ctx.service.utils.resResult(STATUS.SUCCESS, { roleId: role.roleId });
        }
        return ctx.service.utils.resResult(STATUS.ROLE_NOT_FOUND);
    }

    public async createRole(serverId: number, distinctId: string) {
        console.log('enter Auth createRole');
        const ctx = this.ctx;
        const { uid } = ctx;
        const exist = await RoleModel.exists({ 'userInfo.uid': uid, serverId });
        if (exist === true) {
            return ctx.service.utils.resResult(STATUS.ROLE_EXIST);
        }
        const server = await ServerlistModel.findByServerId(serverId);
        if(!server) return ctx.service.utils.resResult(STATUS.SERVER_NOT_FOUND);
        if(nowSeconds() > server.stopRegisterTime) return ctx.service.utils.resResult(STATUS.SERVER_STOP_REGISTER);

        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, lv: DEFAULT_LV, exp: (getExpByLv(DEFAULT_LV - 1) || { sum: 0 }).sum || 0 }, distinctId);
        if (role) {
            await ServerlistModel.incRoleCnt(serverId);
            if(server.isReview) { // 审核服跳关卡
                await this.skipPrologueWhenReview(roleId);
            }
            return ctx.service.utils.resResult(STATUS.SUCCESS, { roleId: role.roleId });
        }
        return ctx.service.utils.resResult(STATUS.ROLE_NOT_FOUND);
    }

    private async skipPrologueWhenReview(roleId: string) {
        const fromWarId = 101, toWarId = 103;
        let warStars: WarStar[] = [];     
        let insertParams: DicWar[] = [];
        for(let i = fromWarId; i <= toWarId; i++) {
            let dicWar = gameData.war.get(i);
            insertParams.push(dicWar);
            if(i < toWarId) warStars.push({ id: dicWar.war_id, warType: dicWar.warType, star: 0, stars: [] });
        }
        await RScriptRecordModel.insertScripts(roleId, insertParams, [toWarId]);
        await RoleModel.updateRoleInfo(roleId, { warStar: warStars, mainWarId: toWarId - 1 })
    }

    /**
     * 绑定账号
     * @param tel 手机号
     * @param code 验证码
     */
    public async bind(tel: string, code: string) {
        const ctx = this.ctx;
        // 参数检查
        const telVerify = this.checkTelNo(tel);
        if (telVerify.status !== 0) {
            return telVerify.resResult;
        }

        if (!isString(code) || code.length !== 6) {
            return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        }

        // 手机验证码核验
        const smsValid: boolean = await smsModel.validateSms(tel, code);
        if (!smsValid) {
            const sms = await smsModel.findByTel(tel);
            if (sms && sms.isFixed) { // 固定手机号登录
                if (sms.code !== code) {
                    return ctx.service.utils.resResult(STATUS.SMS_INVALID);
                }
            } else {
                return ctx.service.utils.resResult(STATUS.SMS_INVALID);
            }
        }

        let telUser = await UserModel.findUserByTel(tel);
        if (telUser && telUser.uid != ctx.uid) {
            return ctx.service.utils.resResult(STATUS.TEL_HAS_USED);
        }

        let user = await UserModel.bindTel(ctx.uid, tel);
        if (!user) return ctx.service.utils.resResult(STATUS.ACCOUNT_NOT_GUEST);
        let param = this.getReturnParam(user, user.deviceId);
        return ctx.service.utils.resResult(STATUS.SUCCESS, param);
    }

    /**
     * 实名认证
     * @param password 密码
     */
    public async authentication(name: string, idNum: string) {
        const ctx = this.ctx;
        // TODO 接SDK
        console.log(name, idNum);
        // let result = await authenticate(name, idNum, ctx.userCode, ctx.pkgName);
        // if (!result) return ctx.service.utils.resResult(STATUS.AUTHEN_FAIL);

        let birthday = this.getBirthdayByIdCard(idNum);
        let user = await UserModel.authentication(ctx.uid, birthday, '');
        let param = this.getReturnParam(user, user.deviceId);
        return ctx.service.utils.resResult(STATUS.SUCCESS, param);
    }

    private getBirthdayByIdCard(idNum: string) {
        let year = idNum.slice(6, 10);
        let month = idNum.slice(10, 12);
        let date = idNum.slice(12, 14);
        return `${year}-${month}-${date}`;
    }

    /**
     * 渠道服登录
     * @returns 
     */
    public async channelLogin(params: {
        channelType: string, pst: string, clientId: string, deviceId: string, platform: string, platformAppid: string, childGameId: number, pkgName: string, serverType: string, getuiCID: string, distinctId: string
    }) {
        const { channelType, pst, clientId, deviceId, platform, platformAppid, childGameId, pkgName, serverType, getuiCID } = params;
        
        const ctx = this.ctx;

        let requestResult = await loginValidata(channelType, { clientId, pst, platform, platformAppid, childGameId });
        if(!requestResult) return this.ctx.service.utils.resResult(STATUS.CHANNEL_ERR);

        if(requestResult.code != 1) {
            return this.ctx.service.utils.resResult(STATUS.VALIDATE_ERR, requestResult);
        }

        let channelId = getChannelId(channelType, requestResult.data.uid);
        const token = ctx.service.utils.generateStr(256);
        let { user, deviceId: oldDeviceId } = await UserModel.createOrUpdateChannelUser(channelId, channelType, {
            ...requestResult.data, childGameId:`${childGameId}`, platformAppid
        }, token, platform, pkgName, serverType, deviceId, ctx.clientIp);
        if(user && user.userCode) {
            ctx.service.utils.checkOnlineUser(user.userCode);
        }

        if (getuiCID) {//更新个推cid
            await UserModel.updateGetuiCIDByChannel(channelId, getuiCID);
        }
        let channelInfo: any = {};
        if(channelType == '37') {
            channelInfo.uid = (<LoginValidateData37>user.channelInfo).uid;
        }
        return ctx.service.utils.resResult(STATUS.SUCCESS, {
            canLogin: true,
            channelId,
            token: user.token,
            userCode: user.userCode,
            channelInfo,
            deviceId: oldDeviceId
        });

    }
    
    public async deleteRole(roleId: string, magicWord: string) {
        console.log('enter Auth deleteRole');
        const ctx = this.ctx;
        if(magicWord != DEBUG_MAGIC_WORD) {
            return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        }
        if(!isDevelopEnv(ctx.app.config.realEnv)) {
            return ctx.service.utils.resResult(STATUS.DEVELOP_ONLY);
        }
        let result = await deletRole(roleId);
        if(!result) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        return ctx.service.utils.resResult(STATUS.SUCCESS);
    }

}
