import { COUNTER } from './../consts';
import { CounterAllModal } from './CounterAll';
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, mongoose, ReturnModelType } from '@typegoose/typegoose';
import { nowSeconds } from '../pubUtils/timeUtil';
const bcrypt = require('bcrypt');
const SALT_WORK_FACTOR = 5


/**
  * GM账号字段接口
*/
@index({ uid: 1 })

export default class GMUser extends BaseModel {
    @prop({ required: true })
    uid: number;

    @prop({ required: true })
    name: string;

    @prop({ required: true })
    username: string;

    @prop({ required: true })
    groupId: number;

    @prop({ required: true, type: String })
    envs: string[];

    @prop({ required: true, default: true })
    isEnable: boolean;

    @prop({ required: true })
    password: string;

    @prop({ required: true })
    salt: string;

    @prop({ required: true })
    token: string;

    @prop({ required: true })
    expireTime: number;

    @prop({ required: true })
    type: number;        // 1-37账号登录 2-我方账号登录

    public static async updateInfo(uid: number, params: GMUserUpdate) {
        let user = await GMUserModel.findOneAndUpdate({ uid }, params, { new: true }).lean();
        return user;
    }

    private static async encryptPass(password: string, salt?: string) {
        if (!salt) {
            salt = await bcrypt.genSalt(SALT_WORK_FACTOR);
        }
        let npassword = await bcrypt.hash(password, salt);
        return { npassword, salt };
    }

    public static async getGmAccountList(lean = true) {
        const user: GMUserType[] = await GMUserModel.find().select('uid username name token envs groupId isEnable type').lean(lean);
        return user;
    }

    public static async getGmAccountByToken(token: string, lean = true) {
        // console.log(token)
        const user: GMUserType = await GMUserModel.findOne({ token }).select('uid username name token envs groupId isEnable expireTime').lean(lean);
        return user;
    }

    public static async getGmAccountByUid(uid: number, lean = true) {
        const user: GMUserType = await GMUserModel.findOne({ uid }).select('uid username name token envs groupId isEnable').lean(lean);
        return user;
    }

    public static async getGmAccountByUsername(username: string, lean = true) {
        const user: GMUserType = await GMUserModel.findOne({ username }).select('uid username name token envs groupId isEnable').lean(lean);
        return user;
    }

    public static async login(username: string, password: string, token: string, lean = true) {
        const user: GMUserType = await GMUserModel.findOne({ username }).select('salt').lean();
        if (user) {
            let { salt } = user;
            let { npassword } = await this.encryptPass(password, salt);
            const checkUser: GMUserType = await GMUserModel.findOneAndUpdate({ username, password: npassword }, { $set: { token, expireTime: nowSeconds() + 24 * 60 * 60 } }).select('uid username name token envs groupId isEnable type').lean(lean);
            return checkUser;
        } else {
            return null
        }
    }

    public static async channelLogin(username: string, token: string) {
        const user: GMUserType = await GMUserModel.findOneAndUpdate({ username }, { $set: { token, expireTime: nowSeconds() + 1 * 60 * 60 } }, {new: true}).select('token type').lean();
        return user;
    }

    public static async createGmAccount(username: string, password: string, name: string, token: string, lean = true) {
        const uid = await CounterAllModal.getNewCounter(COUNTER.GMUID);
        let r = await this.encryptPass(password);
        const user: GMUserType = await GMUserModel.findOneAndUpdate({ username }, { uid, password: r.npassword, salt: r.salt, name, token }, { upsert: true, new: true }).select('uid username name').lean(lean);
        return user;
    }

    public static async changePass(uid: number, password: string, lean = true) {
        let r = await this.encryptPass(password);
        const user: GMUserType = await GMUserModel.findOneAndUpdate({ uid }, { password: r.npassword, salt: r.salt }).select('uid username name').lean(lean);
        return user;
    }
}

export let GMUserModel: ReturnModelType<typeof GMUser, {}>;
export function loadGMUserModel(connect: mongoose.Connection) {
    GMUserModel = getModelForClass(GMUser, {
        existingConnection: connect
    });
}

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