package service

import (
	"crypto/sha1"
	"database/sql"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"gopkg.in/guregu/null.v3"
	"log"
	"strings"
	"time"

	"gopkg.in/redis.v2"

	"xiaoniaokuaiyan.com/xiaoniao/config"
	"xiaoniaokuaiyan.com/xiaoniao/constants"
	dal "xiaoniaokuaiyan.com/xiaoniao/dal"
	"xiaoniaokuaiyan.com/xiaoniao/entity"
	server "xiaoniaokuaiyan.com/xiaoniao/server"
	util "xiaoniaokuaiyan.com/xiaoniao/util"
)

const PASSWORD_KEY string = "2015bird2015assay2015"

type UserService struct {
	server.UserService
	dal.IUser
}

/*var USER_NOT_EXISTS_ERROR = errors.New("user account not exists")
var USER_ALREADY_EXISTS_ERROR = errors.New("account already regist")

func getUser(userName string) (*entity.User, error) {
	db := util.GetSqlDB()
	strSql := "select ID, CUSTOM_MOBILE, CUSTOM_PASSWORD, custom_salt as CUSTOM_SALT from custom where custom_mobile = ? limit 1"
	var user entity.User
	err := db.Get(&user, strSql, userName)
	if err != nil {
		return nil, USER_NOT_EXISTS_ERROR
	}
	return &user, nil

}*/

func (userService *UserService) Login(params map[string]string) (interface{}, error) {
	loginType := params["type"]
	mobile := params["mobile"]
	if loginType != "wx" && loginType != "zfb" && loginType != "trd" {
		if ok := util.IsMobile(mobile); !ok {
			return nil, errors.New("1::手机号码有误!")
		}
	}
	isNew := true
	switch loginType {
	case "normal":
		user, err := userService.IUser.Get(mobile)
		if err != nil {
			return nil, errors.New("3::用户不存在,请先注册")
		}
		password := params["password"]
		if password == "" {
			return nil, errors.New("2::密码不能为空")
		}
		dstPwd := encryptPassword(PASSWORD_KEY + password + user.PasswordSalt)
		if dstPwd != user.Password {
			return nil, errors.New("4::password incorrect")
		}
	case "vcode":
		vcode := params["vcode"]
		_, err := dal.DefaultSMSCodeDal.Get(mobile, vcode, int(constants.SMSCODE_LOGIN))
		if err != nil {
			return nil, errors.New("5::验证码错误")
		}

		userTemp, err := userService._registUser(mobile, false)
		if err != nil {
			return nil, errors.New("regist failed")
		}
		if userTemp != nil {
			isNew = userTemp.IsNew
		}
		go func() {
			db := util.GetWriteSqlDB()
			db.Exec("update t_sms_code set is_used = 1 where mobile=? and code_type = ? and code=?", mobile, constants.SMSCODE_LOGIN, vcode)
			db.Exec("update t_custom set is_accept_up = 'Y' where mobile = ?;", mobile)
			unionId := params["unionId"]
			if len(unionId) > 0 {
				db.Exec("update t_custom set unionid = ? where mobile = ?;", unionId, mobile)
			}
			//20220530 保存三方openid
			if openidtrd, ok := params["openid_trd"]; ok && len(strings.TrimSpace(openidtrd)) > 0 {
				var extra = map[string]interface{}{}
				if userTemp.Extra.Valid {
					json.Unmarshal([]byte(userTemp.Extra.String), &extra)
				}
				var key = "openid_trd"
				extra[key] = openidtrd
				buf, _ := json.Marshal(extra)
				um := entity.User{
					Mobile: mobile,
					Extra:  string(buf),
				}
				_, err = userService.IUser.Update(&um)
			}
		}()
	case "wx":
		unionId := params["unionId"]
		user, err := userService.IUser.GetUserByUnionid(unionId)
		if err != nil {
			return nil, errors.New("3::用户不存在,请先注册")
		}
		isNew = false
		mobile = user.Mobile
	case "mp":
		//qz add 20201124 小程序注册,
		userTemp, err := userService._registUser(mobile, false)
		if err != nil {
			return nil, errors.New("regist failed")
		}
		if userTemp != nil {
			isNew = userTemp.IsNew
		}

		param := map[string]interface{}{}
		//var openid interface{}

		if userTemp.Extra.Valid { //&& userTemp.AccountType == 1
			json.Unmarshal([]byte(userTemp.Extra.String), &param)
			//openid = param[openidKey]
		}
		param["openid_mp"] = params["openid_mp"]

		extraStr, err := json.Marshal(param)
		if err != nil {
			return nil, errors.New("7::type mp update extra error :" + err.Error())
		}
		go func() {
			db := util.GetWriteSqlDB()
			db.Exec("update t_custom set is_accept_up = 'Y' where mobile = ?;", mobile)
			unionId := params["unionId"]
			if len(unionId) > 0 {
				db.Exec("update t_custom set unionid = ?,extra = ? where mobile = ?;", unionId, string(extraStr), mobile)
			}
		}()
	case "zfb": //支付宝小程序登录
		zfbUserId := params["user_zfb_id"]
		user, err := userService.IUser.GetUserByUserId(zfbUserId)
		if err != nil {
			return nil, errors.New("3::用户不存在,请先注册")
		}
		isNew = false
		mobile = user.Mobile
	case "mini": //支付宝小程序注册
		userTemp, err := userService._registUser(mobile, false)
		if err != nil {
			return nil, errors.New("regist failed")
		}
		if userTemp != nil {
			isNew = userTemp.IsNew
		}

		param := map[string]interface{}{}
		//var openid interface{}

		if userTemp.Extra.Valid { //&& userTemp.AccountType == 1
			json.Unmarshal([]byte(userTemp.Extra.String), &param)
			//openid = param[openidKey]
		}
		param["user_zfb_id"] = params["user_zfb_id"]

		extraStr, err := json.Marshal(param)
		if err != nil {
			return nil, errors.New("7::type mp update extra error :" + err.Error())
		}
		go func() {
			db := util.GetWriteSqlDB()
			db.Exec("update t_custom set is_accept_up = 'Y' where mobile = ?;", mobile)
			db.Exec("update t_custom set extra = ? where mobile = ?;", string(extraStr), mobile)

		}()
	case "trd":
		//20220530 参照wx 三方openid 登录
		if openidtrd, ok := params["openid_trd"]; ok && len(strings.TrimSpace(openidtrd)) > 0 {
			user, err := userService.IUser.GetUserByUserId(openidtrd)
			if err != nil {
				return nil, errors.New("3::用户不存在,请先注册")
			}
			isNew = false
			mobile = user.Mobile
		} else {
			return nil, errors.New("3::缺少openid_trd")
		}

	default:
		return nil, errors.New("6::unknow login type")
	}
	/*config := nsq.NewConfig()
	producer, _ := nsq.NewProducer("127.0.0.1:4150", config)
	producer.Publish("api_logic", []byte("user "+mobile+"logged in"))
	*/
	user, _ := userService.IUser.Get(mobile)

	//todo save user login identifier to redis or somewhere else
	var client *redis.Client = util.GetRedis()
	client.Select(server.REDIS_API_AUTH_DB)
	sessionToken := server.GenerateSessionToken(fmt.Sprintf("%d-%s", user.Id, user.Mobile))
	tokenBytes, err := json.Marshal(sessionToken)
	if err != nil {
		return nil, err
	}
	//sessionId := server.GenerateSessionId(user.Id, source)
	statusCmd := client.Set(sessionToken.Token, string(tokenBytes))
	if err = statusCmd.Err(); err != nil {
		return nil, err
	}
	/*var exp int64
	exp, err = config.IniConf.Section("server").Key("redis_api_session_expire").Int64()
	if err != nil || exp < 30 {
		exp = 60
	}
	client.Expire(sessionToken.Token, time.Minute*time.Duration(exp))*/
	param := map[string]interface{}{}
	var openid interface{}
	var openidKey = "openid"
	if k, ok := params["wx_type"]; ok && k == "mp" {
		openidKey = "openid_mp"
	}
	if user.Extra.Valid && user.AccountType == 1 {
		json.Unmarshal([]byte(user.Extra.String), &param)
		openid = param[openidKey]
	}
	var wxInfo interface{} = nil
	if params["openid"] != "" {
		wxInfo, err = getUserWxInfo(params["openid"])
		if err != nil {
			return nil, err
		}
	}
	user.IsNew = isNew
	return map[string]interface{}{
		"token":  sessionToken.Token,
		"data":   user,
		"openid": openid,
		"wxinfo": wxInfo,
	}, nil
}

func (userService *UserService) LoginV2(params map[string]string) (interface{}, error) {
	mobile := params["mobile"]
	if ok := util.IsMobile(mobile); !ok {
		return nil, errors.New("1::手机号码有误!")
	}

	vcode := params["vcode"]

	_, err := dal.DefaultSMSCodeDal.Get(mobile, vcode, int(constants.SMSCODE_LOGIN))
	if err != nil {
		//return nil, errors.New("5::验证码错误")
	}
	isNewCustom, err := userService._registUserV2(params)
	if err != nil {
		return nil, errors.New("regist failed")
	}
	go func() {
		db := util.GetWriteSqlDB()
		db.Exec("update t_sms_code set is_used = 1 where mobile=? and code_type = ? and code=?", mobile, constants.SMSCODE_LOGIN, vcode)
		db.Exec("update t_custom set is_accept_up = 'Y' where mobile = ?;", mobile)
	}()

	/*config := nsq.NewConfig()
	producer, _ := nsq.NewProducer("127.0.0.1:4150", config)
	producer.Publish("api_logic", []byte("user "+mobile+"logged in"))
	*/
	user, _ := userService.IUser.Get(mobile)

	//todo save user login identifier to redis or somewhere else
	client := util.GetRedis()
	client.Select(server.REDIS_API_AUTH_DB)
	sessionToken := server.GenerateSessionToken(fmt.Sprintf("%d-%s", user.Id, user.Mobile))
	tokenBytes, err := json.Marshal(sessionToken)
	if err != nil {
		return nil, err
	}
	//sessionId := server.GenerateSessionId(user.Id, source)
	statusCmd := client.Set(sessionToken.Token, string(tokenBytes))
	if err = statusCmd.Err(); err != nil {
		return nil, err
	}
	/*var exp int64
	exp, err = config.IniConf.Section("server").Key("redis_api_session_expire").Int64()
	if err != nil || exp < 30 {
		exp = 60
	}
	client.Expire(sessionToken.Token, time.Minute*time.Duration(exp))*/
	param := map[string]interface{}{}
	var openid interface{}
	var openidKey = "openid"
	if k, ok := params["wx_type"]; ok && k == "mp" {
		openidKey = "openid_mp"
	}
	if user.Extra.Valid && user.AccountType == 1 {
		json.Unmarshal([]byte(user.Extra.String), &param)
		openid = param[openidKey]
	}
	var wxInfo interface{} = nil
	if params["openid"] != "" {
		wxInfo, err = getUserWxInfo(params["openid"])
		if err != nil {
			return nil, err
		}
	}
	return map[string]interface{}{
		"token":       sessionToken.Token,
		"data":        user,
		"openid":      openid,
		"wxinfo":      wxInfo,
		"isNewCustom": isNewCustom,
	}, nil
}

func (userService *UserService) LoginCoupons(params map[string]string) (interface{}, error) {
	mobile := params["mobile"]
	//isNew := true
	vcode := params["vcode"]
	_, err := dal.DefaultSMSCodeDal.Get(mobile, vcode, int(constants.SMSCODE_LOGIN))
	if err != nil {
		//return nil, errors.New("5::验证码错误")
	}

	userTemp, err := userService._registUser(mobile, false)
	if err != nil {
		return nil, errors.New("regist failed")
	}
	if userTemp != nil {
		//isNew = userTemp.IsNew
	}
	go func() {
		db := util.GetWriteSqlDB()
		db.Exec("update t_sms_code set is_used = 1 where mobile=? and code_type = ? and code=?", mobile, constants.SMSCODE_LOGIN, vcode)
		db.Exec("update t_custom set is_accept_up = 'Y' where mobile = ?;", mobile)
		unionId := params["unionId"]
		if len(unionId) > 0 {
			db.Exec("update t_custom set unionid = ? where mobile = ?;", unionId, mobile)
		}
	}()
	go func() {
		//20210304此处逻辑 只能插入一次t_login_coupons
		//如果之前下过有效订单发放 99 优惠券;
		//如果之前没下过单,或者单据都是在状态(7,9,14) 发放30 优惠券
		db := util.GetWriteSqlDB()
		//todo 插入 t_login_coupons 只能注册一次
		sqlResult := db.MustExec("insert into t_login_coupons (mobile,is_send) SELECT ?, 0 FROM DUAL WHERE NOT EXISTS(SELECT mobile FROM t_login_coupons WHERE mobile = ?)", mobile, mobile)
		if re, _ := sqlResult.RowsAffected(); re <= 0 {
			return
		}
		client := util.GetRedis()
		client.Select(12)
		client.HSet("coupons_unsend", mobile, time.Now().Format("2006-01-02 15:04:05"))
	}()

	/*config := nsq.NewConfig()
	producer, _ := nsq.NewProducer("127.0.0.1:4150", config)
	producer.Publish("api_logic", []byte("user "+mobile+"logged in"))
	*/
	user, _ := userService.IUser.Get(mobile)

	//todo save user login identifier to redis or somewhere else
	var client = util.GetRedis()
	client.Select(server.REDIS_API_AUTH_DB)
	sessionToken := server.GenerateSessionToken(fmt.Sprintf("%d-%s", user.Id, user.Mobile))
	tokenBytes, err := json.Marshal(sessionToken)
	if err != nil {
		return nil, err
	}
	//sessionId := server.GenerateSessionId(user.Id, source)
	statusCmd := client.Set(sessionToken.Token, string(tokenBytes))
	if err = statusCmd.Err(); err != nil {
		return nil, err
	}
	/*var exp int64
	exp, err = config.IniConf.Section("server").Key("redis_api_session_expire").Int64()
	if err != nil || exp < 30 {
		exp = 60
	}
	client.Expire(sessionToken.Token, time.Minute*time.Duration(exp))*/
	return nil, nil
}

func (userService *UserService) GetHomeInvite(params map[string]string) (interface{}, error) {
	data, _, err := getHomeInviteByOpenid(params["toopenid"])
	if err != nil {
		return nil, err
	}
	return data, nil
}

func getUserWxInfo(openid string) (interface{}, error) {
	var wxInfo = struct {
		Openid     string `db:"openid" json:"openid"`
		Nickname   string `db:"nickname" json:"nickname"`
		Gender     int    `db:"sex" json:"gender"`
		HeadImgUrl string `db:"headimgurl" json:"headimgurl"`
		Subscribe  int    `db:"subscribe" json:"subscribe"`
	}{}
	db := util.GetSqlDB()
	strSql := "select openid, nickname, sex, headimgurl,subscribe from t_wechat_userinfo where openid = ? limit 1;"
	err := db.Get(&wxInfo, strSql, openid)
	if err == sql.ErrNoRows {
		return nil, nil
	}
	return wxInfo, err
}

func (userService *UserService) GetUserWxInfo(openid string) (interface{}, error) {
	return getUserWxInfo(openid)
}

const PASSWORD_SALT_SIZE int = 6

func (userService *UserService) Regist(userName string, password string, vcode string) (interface{}, error) {
	if ok := util.IsMobile(userName); !ok {
		return nil, errors.New("1::invalid user name")
	}
	if strings.Trim(password, " ") == "" {
		return nil, errors.New("2::password required")
	}
	_, err := dal.DefaultSMSCodeDal.Get(userName, vcode, int(constants.SMSCODE_REGIST))
	if err != nil {
		return nil, errors.New("4::验证码错误")
	}
	user, err := userService._registUser(userName, true)
	if err != nil {
		//return user, dal.DBRECORD_ALREADY_EXISTS_ERROR
		if err == errRecordExsits {
			return nil, errors.New("3::手机号已注册")
		}
		return nil, err
	}
	go func() {
		db := util.GetWriteSqlDB()
		db.Exec("update t_sms_code set is_used = 1 where mobile=? and code_type = ? and code=?", userName, constants.SMSCODE_REGIST, vcode)
	}()
	return user, nil
}

var errRecordExsits = errors.New("record already exists")

func (userService *UserService) _registUser(userName string, toCheckReturn bool) (*entity.UserDB, error) {
	//check whether account is already regist
	user, err := userService.IUser.Get(userName)
	if err != nil && err != dal.DBRECORD_NOT_EXISTS_ERROR {
		return nil, err
	}
	if toCheckReturn {
		return nil, errRecordExsits
	}
	db := util.GetWriteSqlDB()
	if user != nil {
		if user.IsAcceptProto != "Y" {
			db.Exec("update t_custom set is_accept_up = 'Y' where mobile = ?;", userName)
		}
		user.IsNew = false
		return user, nil
	}
	var pwdSalt = util.RandNumString(PASSWORD_SALT_SIZE)
	ml := len(userName)
	var password = userName[ml-6:]
	password = encryptPassword(PASSWORD_KEY + password + pwdSalt)
	var fields = map[string]interface{}{
		"mobile":        userName,
		"password":      password,
		"account":       userName,
		"password_salt": pwdSalt,
		"is_accept_up":  "Y",
		"status":        1,
		"created_at":    time.Now().Format("2006-01-02 15:04:05"),
	}
	var sqlStr = util.GenerateInsertSql("t_custom", fields)
	sqlResult, err := db.NamedExec(sqlStr, fields)
	if err != nil {
		return nil, err
	}
	uid, _ := sqlResult.LastInsertId()
	return &entity.UserDB{
		Id:     uid,
		Mobile: userName,
		IsNew:  true,
	}, nil

}

func (userService *UserService) _registUserV2(params map[string]string) (interface{}, error) {
	//check whether account is already regist
	user, err := userService.IUser.Get(params["mobile"])
	if err != nil && err != dal.DBRECORD_NOT_EXISTS_ERROR {
		return nil, err
	}
	db := util.GetWriteSqlDB()
	//已经存在的用户,直接返回
	if user != nil {
		//20230517 判断修改openid 的逻辑
		if params["openid"] != "" {
			var extra string
			//更新openid
			//如果存在 extra 解析 json数据,更新openid
			//如果不存在,直接拼json后更新
			if user.Extra.Valid && strings.TrimSpace(user.Extra.String) != "" {
				var dat map[string]interface{}
				if err := json.Unmarshal([]byte(user.Extra.String), &dat); err == nil {
					log.Println("loginV2 update exist custom's openid ", dat)
					dat["openid"] = params["openid"]
					str, err := json.Marshal(dat)
					if err != nil {
						return nil, errors.New("2::failed to extra openid parse json by loginV2")
					}
					extra = string(str)
				} else {
					return nil, errors.New("3::failed to update openid by loginV2")
				}
			} else {
				extra = fmt.Sprintf(`{"openid":"%s"}`, params["openid"])
			}
			db.Exec("update t_custom set extra = ? where mobile = ?;", extra, params["mobile"])
		}
		if user.IsAcceptProto != "Y" {
			db.Exec("update t_custom set is_accept_up = 'Y' where mobile = ?;", params["mobile"])
		}
		return "N", nil
	}

	var pwdSalt = util.RandNumString(PASSWORD_SALT_SIZE)
	ml := len(params["mobile"])
	var password = params["mobile"][ml-6:]
	password = encryptPassword(PASSWORD_KEY + password + pwdSalt)
	var fields = map[string]interface{}{
		"mobile":        params["mobile"],
		"password":      password,
		"account":       params["mobile"],
		"password_salt": pwdSalt,
		"is_accept_up":  "Y",
		"status":        1,
		"extra":         fmt.Sprintf(`{"openid":"%s"}`, params["openid"]),
		"created_at":    time.Now().Format("2006-01-02 15:04:05"),
	}
	if params["openid"] == "" {
		//delete(fields,"extra")
		fields["extra"] = ""
	}

	tx := db.MustBegin()

	//1.新建用户数据
	var sqlStr = util.GenerateInsertSql("t_custom", fields)

	_, err = tx.NamedExec(sqlStr, fields)
	if err != nil {
		//fmt.Println("split order ", oitem.Id, err)
		tx.Tx.Rollback()
		return nil, errors.New("4::failed to insert t_custom By loginV2")
	}
	//如果toopenid 是null 取消后续操作
	if params["toopenid"] == "" {
		tx.Commit()
		return "Y", nil
	}

	//2.插入t_home_invite 关系
	strSql := "insert into t_home_invite(fromopenid, frommobile, fromnickname, fromheadimg, toopenid,create_time) values (?,?,?,?,?,?)"
	sqlResult := tx.MustExec(strSql, params["openid"], params["mobile"], params["fromnickname"], params["fromheadimg"], params["toopenid"], time.Now().Format("2006-01-02 15:04:05"))
	if ra, _ := sqlResult.RowsAffected(); ra <= 0 {
		tx.Tx.Rollback()
		return nil, errors.New("5::failed to insert t_home_invite By loginV2")
	}
	//3.统计已经存在的关系.如果大于10个,就更新t_agent
	_, count, err := getHomeInviteByOpenid(params["toopenid"])
	if err != nil {
		return nil, errors.New("6::failed to insert t_home_invite By loginV2")
	}
	//
	if count >= 9 { //因为是事务,所以第10条数据还没有提交

		user, err := userService.IUser.GetUserByOpenid(params["toopenid"])
		if err != nil && err != dal.DBRECORD_NOT_EXISTS_ERROR {
			tx.Tx.Rollback()
			return nil, errors.New("7::failed to get user mobile by toopenid By loginV2")
		}

		strSql = "update t_agent set redpacket=1000 ,updatetime = ? where openid=? "
		updateResult := tx.MustExec(strSql, time.Now().Format("2006-01-02 15:04:05"), params["toopenid"])
		if ra, _ := updateResult.RowsAffected(); ra <= 0 {
			strSql = "insert into t_agent(openid, mobile, updatetime,redpacket) values(?,?,?,1000)"
			insertResult := tx.MustExec(strSql, params["toopenid"], user.Mobile, time.Now().Format("2006-01-02 15:04:05"))
			if ra, _ := insertResult.RowsAffected(); ra <= 0 {
				tx.Tx.Rollback()
				return nil, errors.New("8::failed to insert/update t_agent By loginV2")
			}
		}
	}

	tx.Commit()

	if err != nil {
		return nil, err
	}
	return "Y", nil

}

func getHomeInviteByOpenid(openid string) (interface{}, int, error) {
	var homeInvite []struct {
		Fromopenid   null.String `db:"fromopenid" json:"fromopenid"`
		Frommobile   null.String `db:"frommobile" json:"frommobile"`
		Fromnickname null.String `db:"fromnickname" json:"fromnickname"`
		Fromheadimg  null.String `db:"fromheadimg" json:"fromheadimg"`
		ToOpenid     null.String `db:"toopenid" json:"toopenid"`
		CreateTime   null.String `db:"create_time" json:"create_time"`
	}
	db := util.GetSqlDB()
	strSql := "select fromopenid, frommobile, fromnickname, fromheadimg,toopenid,create_time from t_home_invite where toopenid = ? order by create_time asc limit 10;"
	err := db.Select(&homeInvite, strSql, openid)
	if err == sql.ErrNoRows {
		return nil, 0, nil
	}
	return homeInvite, len(homeInvite), err
}

func (userService *UserService) ResetPwd(userName, password, newPassword string) (interface{}, error) {
	user, err := userService.IUser.Get(userName)
	if err != nil {
		return nil, err
	}
	if user == nil {
		return nil, errors.New("找不到用户")
	}
	password = encryptPassword(PASSWORD_KEY + password + user.PasswordSalt)
	if password != user.Password {
		return nil, errors.New("密码错误")
	}
	var pwdSalt = util.RandNumString(PASSWORD_SALT_SIZE)
	newPassword = encryptPassword(PASSWORD_KEY + newPassword + pwdSalt)
	um := entity.User{
		Id:           user.Id,
		Password:     newPassword,
		PasswordSalt: pwdSalt,
	}
	r, err := userService.IUser.Update(&um)
	if err != nil {
		return nil, err
	}
	return r, nil
}
func (userService *UserService) ForgetPwd(userName, vcode string, password string) (interface{}, error) {
	code, err := dal.DefaultSMSCodeDal.Get(userName, vcode, int(constants.SMSCODE_FORGOT_PASSWORD))
	if code == nil || code.Mobile == "" {
		return nil, errors.New("1::验证码错误")
	}
	var pwdSalt = util.RandNumString(PASSWORD_SALT_SIZE)
	password = encryptPassword(PASSWORD_KEY + password + pwdSalt)
	um := entity.User{
		Mobile:       userName,
		Password:     password,
		PasswordSalt: pwdSalt,
	}
	r, err := userService.IUser.Update(&um)
	if err != nil {
		return nil, err
	}
	go func() {
		db := util.GetWriteSqlDB()
		db.Exec("update t_sms_code set is_used = 1 where mobile=? and code_type = ? and code=?", userName, constants.SMSCODE_REGIST, vcode)
	}()
	return r, nil
}

func (userService *UserService) SetOpenid(mobile string, openid string, wxType string) (interface{}, error) {
	if ok := util.IsMobile(mobile); !ok {
		return false, errors.New("1::invalid mobile")
	}
	openid = strings.Trim(openid, " ")
	if openid == "" {
		return false, errors.New("2::openid is empty")
	}
	user, err := userService.IUser.Get(mobile)
	if err != nil {
		return nil, err
	}
	var extra = map[string]interface{}{}
	if user != nil && user.Extra.Valid {
		json.Unmarshal([]byte(user.Extra.String), &extra)
	}
	var key = "openid"
	if wxType == "mp" {
		key = "openid_mp"
	}
	extra[key] = openid
	buf, _ := json.Marshal(extra)
	um := entity.User{
		Mobile: mobile,
		Extra:  string(buf),
	}
	_, err = userService.IUser.Update(&um)
	if err != nil {
		return false, err
	}
	return true, nil
}

func (userService *UserService) UpdateUserinfo(uinfo *entity.User) (interface{}, error) {
	toUpUinfo := entity.User{
		Id:     uinfo.Id,
		Avatar: uinfo.Avatar,
	}
	return userService.IUser.Update(&toUpUinfo)
}

func (userService *UserService) GetQueueNotice(mobile string) (interface{}, error) {
	return userService.IUser.GetNotice(mobile)
}

func (userService *UserService) UpdateQueueNotice(notice *entity.QueueNotice) (interface{}, error) {
	return userService.IUser.UpdateNotice(notice)
}

func (userService *UserService) GetRelationship() (interface{}, error) {
	relationStr := config.IniConf.Section("server").Key("user_relationship").Value()
	return strings.Split(relationStr, ","), nil
}

func encryptPassword(source string) string {
	dst := sha1.Sum([]byte(source))
	dstStr := hex.EncodeToString(dst[0:])
	return strings.ToUpper(dstStr)
}

func (userService *UserService) SaveInfo(uinfo *entity.User) (interface{}, error) {
	toUpUinfo := entity.User{
		Id:       uinfo.Id,
		Height:   uinfo.Height,
		Weight:   uinfo.Weight,
		Gender:   uinfo.Gender,
		BirthDay: uinfo.BirthDay,
	}
	return userService.IUser.Update(&toUpUinfo)
}

func (userService *UserService) SaveHobby(uinfo *entity.User) (interface{}, error) {
	toUpUinfo := entity.User{
		Id:    uinfo.Id,
		Hobby: uinfo.Hobby,
	}
	return userService.IUser.Update(&toUpUinfo)
}

func (userService *UserService) GetHobby() (interface{}, error) {
	db := util.GetSqlDB()
	result := []struct {
		Id               int         `db:"id"`
		HobbyName        string      `db:"hobby_name"`
		ImgUrlSelected   null.String `db:"img_url_selected"`
		ImgUrlUnSelected null.String `db:"img_url_unselected"`
	}{}

	err := db.Select(&result, "select * from t_custom_hobby ")
	if err != nil {
		return "", errors.New("1::search hobby error: " + err.Error())
	}
	return result, nil
}