package main

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io"
	"strconv"
	"strings"
	"time"

	"github.com/globalsign/mgo/bson"
	"mongo.games.com/goserver/core/basic"
	"mongo.games.com/goserver/core/logger"
	"mongo.games.com/goserver/core/netlib"
	"mongo.games.com/goserver/core/task"

	"mongo.games.com/game/common"
	"mongo.games.com/game/model"
	"mongo.games.com/game/proto"
	login_proto "mongo.games.com/game/protocol/login"
	server_proto "mongo.games.com/game/protocol/server"
	"mongo.games.com/game/srvdata"
)

type TaskLogin struct {
	*login_proto.CSLogin
	*netlib.Session
	Sid            int64
	BackupPromoter string
	flag           login_proto.OpResultCode
	tagkey         int32
	codeValid      bool
}

// in task.Worker goroutine
func (t *TaskLogin) Call(o *basic.Object) interface{} {
	var playerData *model.PlayerData
	acc, retCode := model.AccountIsExist(t.GetUsername(), t.GetUsername(), t.GetPassword(), t.GetPlatform(),
		t.GetTimeStamp(), t.GetLoginType(), t.tagkey, false, t.codeValid)
	switch retCode {
	case common.LoginOk:
		t.flag = login_proto.OpResultCode_OPRC_Sucess

	case common.LoginPasswordError, common.LoginTypeNoExist, common.LoginError:
		t.flag = login_proto.OpResultCode_OPRC_LoginPassError

	case common.LoginTelCodeExpire:
		t.flag = login_proto.OpResultCode_OPRC_TelCodeExpire

	case common.LoginFreeze:
		t.flag = login_proto.OpResultCode_OPRC_AccountBeFreeze

	case common.LoginNew:
		t.flag = login_proto.OpResultCode_OPRC_Login_CreateAccError
		switch t.GetLoginType() {
		case common.LoginTypeGuest: // 游客
			raw := fmt.Sprintf("%v%v", t.GetUsername(), common.GetAppId())
			h := md5.New()
			io.WriteString(h, raw)
			pwd := hex.EncodeToString(h.Sum(nil))

			acc, retCode = model.InsertAccount(t.GetUsername(), pwd, t.GetPlatform(), t.GetChannel(), t.GetPromoter(), t.GetParams(),
				t.GetDeviceOs(), t.GetInviterId(), t.GetPromoterTree(), t.GetPlatformTag(), t.GetPackage(), t.GetDeviceInfo(), t.BackupPromoter, t.tagkey)
			if retCode != common.InsertAccountOk {
				return nil
			}

			var tf bool
			playerData, tf = model.CreatePlayerDataOnRegister(acc.Platform, acc.AccountId.Hex(), 0, "", niceIdMgr.GetRobHeadUrlIdx())
			if playerData == nil || !tf {
				return nil
			}

			t.flag = login_proto.OpResultCode_OPRC_Sucess

		case common.LoginTypeGoogle: // google,facebook
			raw := fmt.Sprintf("%v%v", t.GetUsername(), common.GetAppId())
			h := md5.New()
			io.WriteString(h, raw)
			pwd := hex.EncodeToString(h.Sum(nil))

			acc, retCode = model.InsertTelAccount(t.Username, pwd, t.GetPlatform(), t.GetChannel(), t.GetPromoter(), t.GetParams(),
				t.GetInviterId(), t.GetPromoterTree(), "", pwd, t.GetPlatformTag(), t.GetPackage(), t.DeviceInfo, t.tagkey, t.AccountType, t.GetDeviceOs())
			if retCode != common.InsertAccountOk {
				return nil
			}

			var tf bool
			playerData, tf = model.CreatePlayerDataByThird(acc.Platform, acc.AccountId.Hex(), t.Name, t.HeadUrl)
			if playerData == nil || !tf {
				return nil
			}

			t.flag = login_proto.OpResultCode_OPRC_Sucess

		case common.LoginTypeTelCode:
			// 需要验证码正确
			if !t.codeValid {
				t.flag = login_proto.OpResultCode_OPRC_TelCodeError
			} else {
				// 随机密码
				raw := fmt.Sprintf("%v%v", bson.NewObjectId().Hex(), common.GetAppId())
				h := md5.New()
				io.WriteString(h, raw)
				pwd := hex.EncodeToString(h.Sum(nil))

				// Username 就是手机号
				acc, retCode = model.InsertTelAccount(t.Username, pwd, t.GetPlatform(), t.GetChannel(), t.GetPromoter(), t.GetParams(),
					t.GetInviterId(), t.GetPromoterTree(), t.Username, pwd, t.GetPlatformTag(), t.GetPackage(), t.DeviceInfo, t.tagkey, t.AccountType, t.GetDeviceOs())
				if retCode != common.InsertAccountOk {
					return nil
				}

				var tf bool
				name := fmt.Sprintf("mango%v", acc.SnId)
				playerData, tf = model.CreatePlayerDataByThird(acc.Platform, acc.AccountId.Hex(), name, t.HeadUrl)
				if playerData == nil || !tf {
					return nil
				}

				t.flag = login_proto.OpResultCode_OPRC_Sucess
			}
		}

		if t.flag == login_proto.OpResultCode_OPRC_Sucess && playerData != nil { // playerData != nil 表示新用户
			// 新账号奖励
			err := model.UpdatePlayerCoin(playerData.Platform, playerData.SnId, playerData.Coin+int64(model.GameParamData.NewPlayerCoin), 0, 0, time.Now().Unix(), time.Now().Unix(), 0, playerData.ShopID)
			if err == nil {
				// 新号赠送日志
				LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(playerData.SnId, playerData.Name, playerData.Platform, model.SystemFreeGive_GiveType_NewPlayer, model.SystemFreeGive_CoinType_Coin, int64(model.GameParamData.NewPlayerCoin)))
				// 帐变记录
				log := model.NewCoinLogEx(&model.CoinLogParam{
					Platform:   playerData.Platform,
					SnID:       playerData.SnId,
					ChangeType: common.BillTypeCoin,
					ChangeNum:  int64(model.GameParamData.NewPlayerCoin),
					RemainNum:  playerData.Coin + int64(model.GameParamData.NewPlayerCoin),
					Add:        0,
					LogType:    common.GainWay_NewPlayer,
					GameID:     0,
					GameFreeID: 0,
					BaseCoin:   0,
					Operator:   "",
					Remark:     "",
				})
				if log != nil {
					LogChannelSingleton.WriteLog(log)
				}
			}

			// 发送绑定手机号奖励
			if t.GetAccountType() == common.AccountTypeTel {
				freeFunc := func(coin int64, diamond int64, item map[int32]int64) {
					err := model.UpdatePlayerCoin(playerData.Platform, playerData.SnId, playerData.Coin+coin, playerData.Diamond+diamond, 0, time.Now().Unix(), time.Now().Unix(), 0, playerData.ShopID)
					if err == nil {
						// 金币
						if coin > 0 {
							LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(playerData.SnId, playerData.Name, playerData.Platform, model.SystemFreeGive_GiveType_BindTel, model.SystemFreeGive_CoinType_Coin, coin))
							// 帐变记录
							log := model.NewCoinLogEx(&model.CoinLogParam{
								Platform:   playerData.Platform,
								SnID:       playerData.SnId,
								ChangeType: common.BillTypeCoin,
								ChangeNum:  coin,
								RemainNum:  playerData.Coin + coin,
								Add:        0,
								LogType:    common.GainWay_BindTel,
								GameID:     0,
								GameFreeID: 0,
								BaseCoin:   0,
								Operator:   "",
								Remark:     "",
							})
							if log != nil {
								LogChannelSingleton.WriteLog(log)
							}
						}
						// 钻石
						if diamond > 0 {
							LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(playerData.SnId, playerData.Name, playerData.Platform, model.SystemFreeGive_GiveType_BindTel, model.SystemFreeGive_CoinType_Diamond, diamond))
							// 帐变记录
							log := model.NewCoinLogEx(&model.CoinLogParam{
								Platform:   playerData.Platform,
								SnID:       playerData.SnId,
								ChangeType: common.BillTypeDiamond,
								ChangeNum:  diamond,
								RemainNum:  playerData.Diamond + diamond,
								Add:        0,
								LogType:    common.GainWay_BindTel,
								GameID:     0,
								GameFreeID: 0,
								BaseCoin:   0,
								Operator:   "",
								Remark:     "",
							})
							if log != nil {
								LogChannelSingleton.WriteLog(log)
							}
						}
						//todo道具

					}
				}

				var coin, diamond int64
				items := map[int32]int64{}
				for k, v := range PlatformMgrSingleton.GetPlatform(acc.Platform).BindTelReward {
					switch k {
					case 1: // 金币
						coin += v
					case 2: // 钻石
						diamond += v
					default:
						// 道具
						items[k] = items[k] + v
					}
				}
				freeFunc(coin, diamond, items)
			}
		}
	}

	return acc
}

// in laucher goroutine
func (t *TaskLogin) Done(i interface{}, tt task.Task) {
	acc, _ := i.(*model.Account)
	SCLogin(t.Session, t.Sid, t.CSLogin, acc, t.flag)

	// 账号冻结
	if t.flag == login_proto.OpResultCode_OPRC_AccountBeFreeze {
		ssDis := &login_proto.SSDisconnect{
			SessionId: proto.Int64(t.Sid),
			Type:      proto.Int32(common.KickReason_Freeze),
		}
		proto.SetDefaults(ssDis)
		t.Send(int(login_proto.GatePacketID_PACKET_SS_DICONNECT), ssDis)
	}

	// 登录成功
	if t.flag == login_proto.OpResultCode_OPRC_Sucess {
		// 标记当前玩家登录成功，断开其它连接
		lss := LoginStateMgrSington.LoginFinish(t.GetUsername(), t.GetPlatform(), t.Sid, acc, t.tagkey)
		if len(lss) != 0 {
			for k, ls := range lss {
				ssDis := &login_proto.SSDisconnect{
					SessionId: proto.Int64(k),
					Type:      proto.Int32(common.KickReason_OtherLogin),
				}
				proto.SetDefaults(ssDis)
				t.Send(int(server_proto.SSPacketID_PACKET_SS_DICONNECT), ssDis)
				logger.Logger.Warnf("==========顶号 oldsid:%v newsid:%v", k, t.Sid)
				LoginStateMgrSington.Logout(ls)
				//todo:game->rehold
			}
		}
	} else {
		//清理登录状态
		LoginStateMgrSington.LogoutBySid(t.Sid)
	}
}

func SCLogin(s *netlib.Session, sid int64, csLogin *login_proto.CSLogin, acc *model.Account, code login_proto.OpResultCode) {
	if s == nil || csLogin == nil {
		return
	}
	sclogin := &login_proto.SCLogin{
		OpRetCode:   code,
		ClientParam: string(model.ClinetBuf),
	}
	if acc != nil {
		now := time.Now()
		sclogin.AccId = proto.String(acc.AccountId.Hex())
		sclogin.SrvTs = proto.Int64(now.Unix())
		if code == login_proto.OpResultCode_OPRC_Sucess {
			acc.LastLoginTime = now
			acc.LoginTimes++
			//获取平台名称
			if acc.Platform != common.Platform_Rob {
				if acc.AccountType == common.AccountTypeTel {
					sclogin.Token = acc.TelPassWord // 密码和appid
				}
				// 版本号
				deviceOs := csLogin.GetDeviceOs()
				packVers := srvdata.GetPackVers(csLogin.GetPlatformTag())
				if deviceOs != "" && packVers != nil {
					if cvers, ok := packVers[deviceOs]; ok {
						sclogin.MinApkVer = proto.Int32(cvers.MinResVer)
						sclogin.LatestApkVer = proto.Int32(cvers.LatestApkVer)
						sclogin.MinApkVer = proto.Int32(cvers.MinApkVer)
						sclogin.LatestResVer = proto.Int32(cvers.LatestResVer)
					}
				}
				gameVers := srvdata.GetPackVers(csLogin.GetPlatformTag())
				if gameVers != nil {
					for k, v := range gameVers {
						token := strings.Split(k, ",")
						if len(token) == 2 && token[1] == deviceOs {
							if gameId, err := strconv.Atoi(token[0]); err == nil {
								sclogin.SubGameVer = append(sclogin.SubGameVer, &login_proto.GameVer{
									GameId:       proto.Int(gameId),
									MinApkVer:    proto.Int32(v.MinApkVer),
									LatestApkVer: proto.Int32(v.LatestApkVer),
									MinResVer:    proto.Int32(v.MinResVer),
									LatestResVer: proto.Int32(v.LatestResVer),
								})
							}
						}
					}
				}
				// 游戏配置
				gps := PlatformMgrSingleton.GetGameFrees(acc.Platform)
				for _, v := range gps {
					if v.Status {
						if v.DbGameFree.GetGameRule() != 0 {
							// 平台游戏
							lgi := &login_proto.LoginGameInfo{
								GameId:  proto.Int32(v.DbGameFree.GetGameId()),
								LogicId: proto.Int32(v.DbGameFree.GetId()),
							}
							sclogin.GameInfo = append(sclogin.GameInfo, lgi)
						} else {
							// 三方游戏
							sclogin.ThrGameId = append(sclogin.ThrGameId, v.DbGameFree.Id)
						}
					}
				}
				// 开关
				cfg := PlatformMgrSingleton.GetEntrySwitch(acc.Platform)
				if cfg != nil {
					for _, vv := range cfg.GetDatas() {
						sclogin.EntrySwitch = append(sclogin.EntrySwitch, vv)
					}
				}
				// 比例
				ct, cr := PlatformMgrSingleton.GetCurrencyByPackageTag(csLogin.PlatformTag)
				sclogin.CurrencyType = ct
				sclogin.CurrencyRatio = cr
			}
		}
	}
	proto.SetDefaults(sclogin)
	common.SendToGate(sid, int(login_proto.LoginPacketID_PACKET_SC_LOGIN), sclogin, s)
}
