package main

import (
	"time"

	"../log"
	"../mod"
	"../nnet"
	"../nt"
	pb "../protos"
	"../utils"
	"github.com/coheneye/go-simplejson"
	"go.uber.org/zap"
)

func login_dispatch(ses nnet.ISession, pkt *LoginPacket) {
	js, err := simplejson.NewJson(pkt.body)
	if nil != err {
		log.Error("json.Unmarshal", zap.Error(err))
		return
	}

	cmd := js.Get("cmd").MustString()
	//	ec := js.Get("ec").MustInt()
	if cmd != "status" && len(cmd) > 0 {
		log.Debug("login_dispatch", zap.String("cmd", cmd), zap.String("json", string(pkt.body)))
	}

	switch cmd {
	case "verify": // token 验证，同步返回客户端，其他不用同步操作，服务器内部消化
		do_login_verify(js)
	case "status": // 心跳
	case "upgrade": // 绑定手机号
		do_login_upgrade(js)
	case "changep": // 修改密码
		do_login_changep(js)
	case "alter": // 修改用户信息
	default:
		do_login_default(cmd, js)
	}
}

// 取消等待 Login 返回登录验证的超时计时
func cancel_inner_timeout(guid uint64) {
	v, err := LoginStatus.VerifyTimeout.Peek(guid)
	if err != nil {
		log.Warn("not", zap.Uint64("guid", guid))
		return
	}
	tm, ok := v.(*time.Timer)
	if !ok {
		log.Error("interface error")
		return
	}
	tm.Stop()
}

//
func do_login_verify(js *simplejson.Json) {
	result := js.Get("result")
	ec := js.Get("ec").MustInt()
	guid := result.Get("guid").MustUint64()
	s_login := &pb.S_Login{}

	// 取得缓存的session
	ises, err := ServerStatus.TmpSessions.Peek(guid)
	if err != nil {
		log.Error("ses not found", zap.Int("ec", ec), zap.Uint64("guid", guid))
		//
		ServerStatus.NewUserFlag.Remove(guid)
		return
	}
	ses, ok := ises.(nnet.ISession)
	if !ok {
		log.Warn("interface trans", zap.Uint64("guid", guid))
		ServerStatus.NewUserFlag.Remove(guid)
		return
	}

	// 取消超时等待
	cancel_inner_timeout(guid)

	// 验证失败
	if ec != 0 {
		log.Error("login", zap.Int("ec", ec))
		s_login.Ec = int32(pb.ErrCode_TOKEN_ERR)
	} else {
		// 初始信息
		nickname := result.Get("nickname").MustString()
		phone := result.Get("phone").MustString()
		qq := result.Get("qq").MustString()
		expire := result.Get("expire").MustInt64()
		wechat := result.Get("wechat").MustString()
		channel := result.Get("channel").MustString()
		ip := result.Get("ip").MustString()
		area := result.Get("area").MustString()
		account := result.Get("account").MustString()
		password := result.Get("password").MustString()

		var icon int32 = 1
		var balance int64 = 0
		var bank int64 = 0
		var freezed int64 = 0
		var vip int32 = 1
		var bets int64 = 0
		var recharged int64 = 0

		utils.UnUsed(expire)
		// 需要保存数据
		_, err := ServerStatus.NewUserFlag.Peek(guid)
		if err == nil {
			err = mod.UpdateUserinfoToRedis(guid, map[string]interface{}{
				"nickname":  nickname,
				"password":  password,
				"phone":     phone,
				"qq":        qq,
				"wechat":    wechat,
				"icon":      icon,
				"balance":   balance,
				"bank":      bank,
				"freezed":   freezed,
				"vip":       vip,
				"bets":      bets,
				"recharged": recharged,
				"createdAt": time.Now().Unix(),
				"channel":   channel,
				"ip":        ip,
				"area":      area,
				"account":   account,
				//		"token":token,
			})
			log.Debug("saved userinfo", zap.Uint64("guid", guid))
			s_login.Account = account
			s_login.Nickname = nickname
			s_login.Ip = ip
			s_login.Area = area
			s_login.Phone = phone
			s_login.Qq = qq
			s_login.Wechat = wechat
			s_login.Icon = icon
			s_login.Balance = balance
			s_login.Bank = bank
			s_login.Vip = vip
			s_login.NextVipNeed = GetNextVipNeed(vip)
			s_login.Bets = bets
			// 保存映射
			if err := mod.SaveMapAccountGuid(account, guid); err != nil {
				log.Error("map account guid", zap.Uint64("guid", guid), zap.Error(err))
			}
		} else {
			user, err := mod.GetUserinfoFromRedis(guid)
			if nil != err {
				s_login.Ec = int32(pb.ErrCode_UNKNOWN)
				OnLoginAuthFinished(guid, ses, s_login)
				return
			}
			UserToS_Login(user, s_login)
		}
	}
	OnLoginAuthFinished(guid, ses, s_login)
}

func do_login_status(res *L_Res) {

}

func do_login_upgrade(js *simplejson.Json) {
	result := js.Get("result")
	ec := js.Get("ec").MustInt()
	guid := result.Get("guid").MustUint64()
	password := result.Get("password").MustString()
	phone := result.Get("phone").MustString()

	ses, err := Server.GetSession(guid)
	if nil != err {
		log.Error("GetSession", zap.Uint64("guid", guid))
		return
	}

	cancel_inner_timeout(guid)

	r := &pb.S_BindPhone{}

	if ec != 0 {
		log.Error("upgrade", zap.Uint64("guid", guid), zap.String("password", password),
			zap.String("phone", phone))
		r.Ec = int32(pb.ErrCode_UNKNOWN)
		SendToClient(ses, guid, r)
		return
	} else {
		if len(password) > 0 && len(phone) > 0 {
			r.Password = password
			r.Phone = phone
		} else {
			arr, err := mod.GetUserAttrs(guid, "phone", "password")
			if err != nil {
				log.Error("GetUserAttrs", zap.Uint64("guid", guid), zap.Error(err))
				r.Ec = int32(pb.ErrCode_UNKNOWN)
				SendToClient(ses, guid, r)
				return
			}
			r.Password = utils.If_to_string(arr[1], "")
			r.Phone = utils.If_to_string(arr[0], "")
		}
		SendToClient(ses, guid, r)

		Ev.OnUserBindPhone(guid, r)

		__sendBindPhoneBonus(ses, guid)
	}
}
func __sendBindPhoneBonus(ses nnet.ISession, guid uint64) error {
	//TODO: 优化script
	val, ok := nt.DynConf.Kv["bind_phone_bonus"]
	if !ok {
		// TODO: 如果取消送金，则这不算 warn
		log.Warn("not config bind phone bonus")
		return nil
	}
	bonus := utils.If_to_int64(val, 0)
	if bonus <= 0 {
		log.Warn("bind phone bonus < 0", zap.Int64("bonus", bonus))
		return nil
	}
	err := mod.UpdateUserAttr(guid, "bindPhoneBonus", bonus)
	if nil != err {
		log.Error("bindPhoneBonus", zap.Uint64("guid", guid), zap.Error(err))
		return err
	}
	newBalance, err := mod.AddUserBalance(guid, bonus)
	if nil != err {
		log.Error("AddUserBalance", zap.Uint64("guid", guid), zap.Error(err))
		return err
	}

	Ev.OnUserReward(guid, bonus, newBalance, int32(pb.ReasonBalanceChange_BIND_PHONE), ses)
	return nil
}

func do_login_changep(js *simplejson.Json) {
	result := js.Get("result")
	ec := js.Get("ec").MustInt()
	guid := result.Get("guid").MustUint64()
	password := result.Get("password").MustString()

	r := &pb.S_UpdatePassword{}
	ses, err := Server.GetSession(guid)
	if nil != err {
		log.Error("GetSession", zap.Uint64("guid", guid))
		return
	}

	cancel_inner_timeout(guid)

	if ec != 0 {
		log.Error("changep", zap.Uint64("guid", guid), zap.String("password", password))
		r.Ec = int32(pb.ErrCode_FAILED)
		SendToClient(ses, guid, r)
		return
	} else {
		if len(password) > 0 {
			r.Password = password
		} else {
			pwd, err := mod.GetUserAttr(guid, "password")
			if nil != err {
				log.Error("GetUserPassword", zap.Uint64("guid", guid))
				r.Ec = int32(pb.ErrCode_UNKNOWN)
				SendToClient(ses, guid, r)
				return
			}
			r.Password = pwd
		}
		SendToClient(ses, guid, r)

		Ev.OnUserUpdatePassword(guid, r)
	}
}

func do_login_alter(res *L_Res) {

}

func do_login_default(cmd string, js *simplejson.Json) {
	log.Warn("received login unsupported cmd", zap.String("cmd", cmd))
}
