/**
 * 用户逻辑
 */

import { ADMINTYPE, CODETYPE, MAILTYPE, MEMBERSTATE, MEMBERTYPE, REGISTERSTART, STATE, UNITMEMBERTYPE, USERREGISTERSTATE } from "../../config/enum";
import { ERRORENUM } from "../../config/errorEnum";
import { addOneData } from "../../data/add";
import { TABLEENUM } from "../../data/models/model";
import { findCount, findOnce, findOnceToSort } from "../../data/select";
import { updateOneData } from "../../data/update";
import { generateSMSCode, generateToken, getTodayMs, successResult } from "../../tools/system";
import { BizError } from "../../util/bizError";
import { changeEnumValue } from "../../util/verificationEnum";
import { sendHomePageVerificationCode, sendMail, sendVerificationCode } from "../mail";
import { sendALSMS } from "../sms";



/**
 * 登录
 * @param param0 
 * @returns 
 */
export async function login({loginId, pwd}) {
    let selectParam = { 
        "$or":[
            {loginId:loginId, memberType:MEMBERTYPE.个人会员}, 
            {phone:loginId}, 
            {unitName:loginId, memberType:MEMBERTYPE.单位会员}, 
            {mail:loginId, memberType:MEMBERTYPE.单位会员},
            {loginId:loginId}
        ]
    };
    let userInfo = await findOnce(TABLEENUM.用户表, selectParam);
    
    if (!userInfo || !userInfo.userId) throw new BizError(ERRORENUM.账号或密码错误);

    if (userInfo.isBlackUser == STATE.是) throw new BizError(ERRORENUM.黑名单用户不允许登录, "您的会员服务已过期，如需恢复请联系秘书处：010-86208681");

    if (userInfo.isInput && !userInfo.inputUserChangePwd) {
        return {
            isInput:userInfo.isInput,
            phone:userInfo.phone,
            userId:userInfo.userId,
            isUniversities:UNITMEMBERTYPE.院校 == userInfo.unitMemberType
        }
    }

    if (userInfo.pwd != pwd ) throw new BizError(ERRORENUM.账号或密码错误);

    let token = "";
    const Now = new Date().valueOf();
    token = generateToken(userInfo.userId);
    await updateOneData(TABLEENUM.用户表, {userId:userInfo.userId}, {token, tokenMs:Now, lastLoginMs:Now});

    if (userInfo.memberState >= MEMBERSTATE.冻结 ) {
        throw new BizError(ERRORENUM.该账号已被冻结);
    }
    let isPass = false;
    if (userInfo.userRegisterState == USERREGISTERSTATE.通过) isPass = true;

    let dataInfo = {
        isAdmin:userInfo.isAdmin == STATE.是,
        name:userInfo.isAdmin ? changeEnumValue(ADMINTYPE, userInfo.adminType ) : userInfo.name,
        userId:userInfo.userId,
        token:token,
        adminLv:userInfo.adminLv,
        timeMs:Now,
        isPass,
        memberType:userInfo.memberType,
        isInput:(userInfo.isInput && !userInfo.inputUserChangePwd),
        phone:userInfo.phone
    };

    return {dataInfo};
}


/**
 * 退出登陆
 * @param userId 
 * @returns 
 */
export async function logout({userId}) {
    let token = generateToken(userId);
    await updateOneData(TABLEENUM.用户表, {userId:userId}, {token});

    return successResult();
}


/**
 * 修改密码
 * @param param0 
 * @returns 
 */
export async function changePwd({userId, phone, pwd, confirmation, code, type}) {
    if (pwd.search(/^[A-Za-z0-9]{6,18}$/) < 0) throw new BizError(ERRORENUM.密码只能由6至18位字符和数字组成);
    if (pwd != confirmation)  throw new BizError(ERRORENUM.两次密码不一致);
    let codeInfo = await findOnce(TABLEENUM.验证码表, {codeNum:code, phone, type:CODETYPE.修改密码, isUse:false});
    if (!codeInfo || !codeInfo.codeNum) {
        throw new BizError(ERRORENUM.验证码错误);
    }
    if (!userId) {
        let selectParam:any = {};
        if (type == 2) selectParam.mail = phone;
        else selectParam.phone = phone;
        let userInfo = await findOnce(TABLEENUM.用户表, selectParam, ["userId", "isInput", "inputUserChangePwd", "unitMemberType", "memberType"]);
        if (!userInfo || !userInfo.userId) throw new BizError(ERRORENUM.手机号不正确);
        if (userInfo.isInput && !userInfo.inputUserChangePwd && (userInfo.memberType == MEMBERTYPE.单位会员 && userInfo.unitMemberType == UNITMEMBERTYPE.院校)) {
            throw new BizError(ERRORENUM.密码修改错误);
        }
        // let pwdStr = generatePwd(userInfo.userId, pwd); todo
        let pwdStr = pwd;
        let updateInfo:any = {pwd:pwdStr};

        await updateOneData(TABLEENUM.用户表, {userId:userInfo.userId}, updateInfo);
        await updateOneData(TABLEENUM.验证码表, {codeNum:code, phone, type:CODETYPE.修改密码, isUse:false}, {isUse:true});
    } else {
        //首次登录
        let userInfo = await findOnce(TABLEENUM.用户表, {userId}, ["userId", "isInput" ,"inputUserChangePwd", "phone", "memberType", "unitMemberType"]);
        if (!userInfo.userId) {
            throw new BizError(ERRORENUM.账号不存在)
        }

        let selectParam:any = {};
        if (type == 2) selectParam.mail = phone;
        else selectParam.phone = phone;

        let checkUserInfo = await findOnce(TABLEENUM.用户表, selectParam, ["userId"]);
        if (checkUserInfo && checkUserInfo.userId && checkUserInfo.userId != userInfo.userId) throw new BizError(ERRORENUM.该手机号已被注册);
        if (!userInfo.isInput ) {
            throw new BizError(ERRORENUM.密码修改错误);
        }else if ((userInfo.inputUserChangePwd == true) && (userInfo.memberType == MEMBERTYPE.单位会员 && userInfo.unitMemberType == UNITMEMBERTYPE.院校)) {
            throw new BizError(ERRORENUM.密码修改错误);
        } else {
            let pwdStr = pwd;
            let updateInfo:any = {pwd:pwdStr};
            if (userInfo.isInput && !userInfo.inputUserChangePwd) {
                updateInfo.phone = phone;
                updateInfo.inputUserChangePwd = true;
            }
    
            await updateOneData(TABLEENUM.用户表, {userId:userInfo.userId}, updateInfo);
            await updateOneData(TABLEENUM.验证码表, {codeNum:code, phone, type:CODETYPE.修改密码, isUse:false}, {isUse:true});
        }
    }

    return successResult();
}


/**
 * 个人中心修改密码
 * @param param0 
 * @returns 
 */
export async function changePwdById({userId, oldPwd, pwd, confirmation}) {
    let userInfo = await findOnce(TABLEENUM.用户表, {userId}, ["userId", "isInput", "inputUserChangePwd", "unitMemberType", "memberType", "pwd"]);
    if (userInfo.pwd != oldPwd ) throw new BizError(ERRORENUM.账号或密码错误);

    if (pwd.search(/^[A-Za-z0-9]{6,18}$/) < 0) throw new BizError(ERRORENUM.密码只能由6至18位字符和数字组成);
    if (pwd != confirmation)  throw new BizError(ERRORENUM.两次密码不一致);

    if (userInfo.isInput && !userInfo.inputUserChangePwd && (userInfo.memberType == MEMBERTYPE.单位会员 && userInfo.unitMemberType == UNITMEMBERTYPE.院校)) {
        throw new BizError(ERRORENUM.密码修改错误);
    }
    let pwdStr = pwd;
    let updateInfo:any = {pwd:pwdStr};

    await updateOneData(TABLEENUM.用户表, {userId:userInfo.userId}, updateInfo);
    // await updateOneData(TABLEENUM.验证码表, {codeNum:code, phone:userInfo.phone, type:CODETYPE.修改密码, isUse:false}, {isUse:true});

    return successResult();
}


/**
 * 个人中心修改注册手机号【短信验证码】 success
 * @param userId 
 * @param phone 
 * @returns 
 */
export async function memberChangePhoneSendCode({userId, phone}) {
    let userInfo = await findOnce(TABLEENUM.用户表, {userId}, ["userId"]);
    if (!userInfo || !userInfo.userId) throw new BizError(ERRORENUM.不存在该手机号的账号);
    const NowMs = new Date().valueOf();
    let codeSelectParam = { phone, isUse:false,  type:CODETYPE.修改手机号, sendMs:{"$gt":getTodayMs()} }
    let lastCodeInfo = await findOnceToSort(TABLEENUM.验证码表, codeSelectParam, {sendMs:-1});

    if (lastCodeInfo && lastCodeInfo.codeNum) {
        if ( (lastCodeInfo.sendMs + (60*1000)) > NowMs ) throw new BizError(ERRORENUM.频繁操作请稍后再试);
        /**校验今日同类型验证码次数 */
        let todayNotUseCount = await findCount(TABLEENUM.验证码表, codeSelectParam);
        if (todayNotUseCount >= 4) throw new BizError(ERRORENUM.发送验证码次数超限制, `${phone} 注册验证码超过限制3`);
    }

    const Code = generateSMSCode();//生成短信验证码

    /**发送短信模块 */
    await sendALSMS(Code, phone);
    let addInfo = {codeNum:Code, phone, sendMs:NowMs, type:CODETYPE.修改手机号, isUse:false};
    await addOneData(TABLEENUM.验证码表, addInfo);

    return {code:""};
}


/**
 * 个人中心修改注册手机号
 * @param param0 
 * @returns 
 */
export async function changePhoneById({userId, phone, code}) {
    let userInfo = await findOnce(TABLEENUM.用户表, {userId}, ["userId", "isInput" ,"inputUserChangePwd", "phone", "memberType", "unitMemberType"]);
    if (!userInfo.userId) {
        throw new BizError(ERRORENUM.账号不存在)
    }
    let checkUserInfo = await findOnce(TABLEENUM.用户表, {phone}, ["userId"]);
    if (checkUserInfo && checkUserInfo.userId && checkUserInfo.userId != userInfo.userId) throw new BizError(ERRORENUM.该手机号已被注册);
    
    let codeInfo = await findOnce(TABLEENUM.验证码表, {codeNum:code, phone, type:CODETYPE.修改手机号, isUse:false});
    if (!codeInfo || !codeInfo.codeNum) {
        throw new BizError(ERRORENUM.验证码错误);
    }

    await updateOneData(TABLEENUM.用户表, {userId:userInfo.userId}, {phone});
    await updateOneData(TABLEENUM.验证码表, {codeNum:code, phone, type:CODETYPE.修改手机号, isUse:false}, {isUse:true});

    return successResult();
}

// ----------------------------------------------------

/**
 * 个人中心修改单位邮箱【短信验证码】 success
 * @param userId 
 * @param phone 
 * @returns 
 */
 export async function memberChangeMailSendCode({userId, mail}) {
    let userInfo = await findOnce(TABLEENUM.用户表, {userId}, ["userId"]);
    if (!userInfo || !userInfo.userId) throw new BizError(ERRORENUM.不存在该手机号的账号);
    const NowMs = new Date().valueOf();
    let codeSelectParam = { mail, isUse:false,  type:CODETYPE.修改邮箱, sendMs:{"$gt":getTodayMs()} }
    let lastCodeInfo = await findOnceToSort(TABLEENUM.验证码表, codeSelectParam, {sendMs:-1});

    if (lastCodeInfo && lastCodeInfo.codeNum) {
        if ( (lastCodeInfo.sendMs + (60*1000)) > NowMs ) throw new BizError(ERRORENUM.频繁操作请稍后再试);
        /**校验今日同类型验证码次数 */
        let todayNotUseCount = await findCount(TABLEENUM.验证码表, codeSelectParam);
        if (todayNotUseCount >= 4) throw new BizError(ERRORENUM.发送验证码次数超限制, `${mail} 注册验证码超过限制3`);
    }

    const Code = generateSMSCode();//生成短信验证码

    /**发送邮件验证码模块 */
    await sendHomePageVerificationCode(userId, mail, MAILTYPE.邮箱获取验证码, Code);
    let addInfo = {codeNum:Code, mail, sendMs:NowMs, type:CODETYPE.修改邮箱, isUse:false};
    await addOneData(TABLEENUM.验证码表, addInfo);

    return {code:""};
}


/**
 * 个人中心修改注册单位邮箱
 * @param param0 
 * @returns 
 */
export async function changeMailById({userId, mail, code}) {
    let userInfo = await findOnce(TABLEENUM.用户表, {userId}, ["userId", "isInput" ,"inputUserChangePwd", "phone", "memberType", "unitMemberType"]);
    if (!userInfo.userId) {
        throw new BizError(ERRORENUM.账号不存在)
    }
    let checkUserInfo = await findOnce(TABLEENUM.用户表, {mail}, ["userId"]);
    if (checkUserInfo && checkUserInfo.userId && checkUserInfo.userId != userInfo.userId) throw new BizError(ERRORENUM.该手机号已被注册);
    
    let codeInfo = await findOnce(TABLEENUM.验证码表, {codeNum:code, mail, type:CODETYPE.修改邮箱, isUse:false});
    if (!codeInfo || !codeInfo.codeNum) {
        throw new BizError(ERRORENUM.验证码错误);
    }

    await updateOneData(TABLEENUM.用户表, {userId:userInfo.userId}, {mail});
    await updateOneData(TABLEENUM.验证码表, {codeNum:code, mail, type:CODETYPE.修改邮箱, isUse:false}, {isUse:true});

    return successResult();
}

//----------------------------------------------------



/**
 * 修改密码【短信验证码】 success
 * @param userId 
 * @param phone 
 * @returns 
 */
export async function memberChangePwdSendCode({loginId, phone}) {

    let selectParam = { 
        "$or":[
            {loginId:loginId, memberType:MEMBERTYPE.个人会员}, 
            {phone:loginId}, 
            {unitName:loginId, memberType:MEMBERTYPE.单位会员}, 
            {mail:loginId, memberType:MEMBERTYPE.单位会员},
            {loginId:loginId}
        ]
    };

    let userInfo = await findOnce(TABLEENUM.用户表, selectParam, ["userId", "phone"]);
    if (!userInfo) {
        throw new BizError(ERRORENUM.账号不存在);
    }

    if (userInfo.phone != phone ) throw new BizError(ERRORENUM.手机号不正确); 

    const Code = generateSMSCode();//生成短信验证码

    const NowMs = new Date().valueOf();

    /**发送短信模块 */
    await sendALSMS(Code, phone);
    let addInfo = {codeNum:Code, phone, sendMs:NowMs, type:CODETYPE.修改密码, isUse:false};
    await addOneData(TABLEENUM.验证码表, addInfo);

    return {isSuccess:true};
}


/**
 * 修改密码【邮箱验证码】 success
 * @param userId 
 * @param phone 
 * @returns 
 */
export async function memberMailChangePwdSendCode({loginId, mail}) {
     let selectParam = { 
        "$or":[
            {loginId:loginId, memberType:MEMBERTYPE.个人会员}, 
            {phone:loginId}, 
            {unitName:loginId, memberType:MEMBERTYPE.单位会员}, 
            {mail:loginId, memberType:MEMBERTYPE.单位会员},
            {loginId:loginId}
        ]
    };

    let userInfo = await findOnce(TABLEENUM.用户表, selectParam, ["userId", "mail", "name", "unitName", "memberType"]);
    if (!userInfo) {
        throw new BizError(ERRORENUM.账号不存在);
    }

    if (userInfo.mail != mail ) throw new BizError(ERRORENUM.邮箱不正确); 

    const Code = generateSMSCode();//生成短信验证码

    const NowMs = new Date().valueOf();

    /**发送短信模块 */
    let nameStr = userInfo.memberType == MEMBERTYPE.个人会员 ? userInfo.name : userInfo.unitName;
    sendVerificationCode(mail, nameStr, Code);
    let addInfo = {codeNum:Code, phone:mail, sendMs:NowMs, type:CODETYPE.修改密码, isUse:false};
    await addOneData(TABLEENUM.验证码表, addInfo);

    return {isSuccess:true};
}




