package server

import (
	"encoding/json"
	"game/common/model/user"
	"game/common/proto/pb"
	"game/common/rpc"
	"game/common/utils"
	"github.com/fox/fox/etcd"
	"github.com/fox/fox/ipb"
	"github.com/fox/fox/ksync"
	"github.com/fox/fox/log"
	"github.com/fox/fox/processor"
	"github.com/fox/fox/service"
	"github.com/fox/fox/xrand"
	"time"
)

const (
	timeout = time.Second * 30
)

func (s *LoginService) initProcessor() {
	s.Processor().RegisterMessages(processor.RegisterMetas{
		pb.MsgId_ReqUserLoginId: {pb.ReqUserLogin{}, s.onLoginOrRegister},
	})
}

func (s *LoginService) checkLoginOrRegister(req *pb.ReqUserLogin) (us *user.UserAccount, code pb.ErrCode, node *etcd.ServiceNode) {
	var err error
	node, err = s.BindService().HashServiceNode(pb.ServiceTypeId_STI_DB, xrand.RandN[int64](100))
	if err != nil {
		log.ErrorF(s.Log("not find db service.err:%s ", err.Error()))
		return nil, pb.ErrCode_SystemErr, node
	}
	if req.Version < "20250601123030" {
		return nil, pb.ErrCode_VersionTooLow, node
	}
	us = &user.UserAccount{
		Username:    req.Username,
		Password:    req.Password,
		DeviceID:    req.DeviceId,
		LastLoginIP: req.Ip,
	}
	rpcMsg := ipb.MakeRpcMsg(rpc.GetUserAccount, 0, us)
	rspMsg, err := s.CallByServiceId(int(pb.ServiceTypeId_STI_DB), timeout, rpcMsg)
	if err != nil {
		log.ErrorF(s.Log("call rpc:%v err:%s ", rpcMsg.RpcMsgId, err.Error()))
		return nil, pb.ErrCode_SystemErr, node
	}
	if rspMsg.RpcCode != 0 && rspMsg.RpcCode != int32(pb.ErrCode_AccountNotExist) {
		log.ErrorF(s.Log("call rpc:%v err:%s ", rpcMsg.RpcMsgId, pb.ErrCode(rspMsg.RpcCode)))
		return nil, pb.ErrCode(rspMsg.RpcCode), node
	}
	_ = json.Unmarshal(rspMsg.Msg, us)
	//log.DebugF("收到rpc:%v返回数据:%v", rpcName.GetUserAccount, string(rspMsg.Msg))
	if rspMsg.RpcCode == int32(pb.ErrCode_AccountNotExist) {
		// 没有帐号，创建帐号
		us = &user.UserAccount{
			Username:      req.Username,
			Password:      req.Password,
			DeviceID:      req.DeviceId,
			LastLoginIP:   req.Ip,
			LastLoginTime: time.Now(),
			RegisterIP:    req.Ip,
			RegisterTime:  time.Now(),
		}
		rpcMsg = ipb.MakeRpcMsg(rpc.CreateUserAccount, 0, us)
		rspMsg, err = s.CallByTopic(service.RpcTopicEx(node.Name), timeout, rpcMsg)
		if err != nil {
			log.ErrorF(s.Log("call rpc:%v err:%s ", rpcMsg.RpcMsgId, err.Error()))
			return nil, pb.ErrCode_SystemErr, node
		}
		if rspMsg.RpcCode != 0 {
			log.ErrorF(s.Log("call rpc:%v err:%s ", rpcMsg.RpcMsgId, pb.ErrCode(rspMsg.RpcCode)))
			return nil, pb.ErrCode(rspMsg.RpcCode), node
		}
		_ = json.Unmarshal(rspMsg.Msg, us)
		if us.ID == 0 {
			log.ErrorF(s.Log("call rpc:%v err", rpcMsg.RpcMsgId))
			return nil, pb.ErrCode_SystemErr, node
		}
		log.DebugF("收到rcp:%v返回数据:%v", rpc.CreateUserAccount, string(rspMsg.Msg))
	}
	if !utils.CheckPassword(req.Password, us.Password) {
		log.ErrorF(s.Log("用户密码错误"))
		return nil, pb.ErrCode_LoginUserOrPwdErr, node
	}
	switch us.Status {
	case user.AccountFrozen:
		return nil, pb.ErrCode_AccountFrozen, node
	case user.AccountBanned:
		return nil, pb.ErrCode_AccountBanned, node
	default:
		return us, pb.ErrCode_OK, node
	}
}

// 生成JWT令牌(简化版)
func generateToken(userID int64, username string) (string, error) {
	_ = userID
	_ = username
	// 这里应该使用JWT库生成实际令牌
	// 简化实现，实际项目中请使用安全的JWT实现
	return "generated-token-placeholder", nil
}

// 获取用户数据，如果没有则创建
func (s *LoginService) getUser(accountId int64) (*user.User, pb.ErrCode) {
	node, err := s.BindService().HashServiceNode(pb.ServiceTypeId_STI_DB, xrand.RandN[int64](100))
	if err != nil {
		log.ErrorF(s.Log("not find db service.err:%s ", err.Error()))
		return nil, pb.ErrCode_SystemErr
	}
	us := &user.User{
		AccountId: accountId,
	}
	rpcMsg := ipb.MakeRpcMsg(rpc.GetUserByAccountId, 0, us)
	rsp, err := s.CallByServiceId(int(pb.ServiceTypeId_STI_DB), timeout, rpcMsg)
	if err != nil {
		log.ErrorF(s.Log("call src:%v rpc:%v err:%s", node.Name, rpcMsg.RpcMsgId, err.Error()))
		return nil, pb.ErrCode_SystemErr
	}
	if rsp.RpcCode != 0 {
		log.ErrorF(s.Log("call rpc:%v err:%s ", rpcMsg.RpcMsgId, pb.ErrCode(rsp.RpcCode)))
		return nil, pb.ErrCode(rsp.RpcCode)
	}
	_ = json.Unmarshal(rsp.Msg, us)
	if us.ID == 0 {
		log.ErrorF(s.Log("call rpc:%v return:%v", rpcMsg.RpcMsgId, string(rsp.Msg)))
		return us, pb.ErrCode_SystemErr
	}
	return us, pb.ErrCode_OK
}

// 登录或注册
func (s *LoginService) onLoginOrRegister(iMsg *ipb.InternalMsg, req *pb.ReqUserLogin) {
	ksync.GoSafe(func() {
		account, code, node := s.checkLoginOrRegister(req)
		userId := int64(0)
		rsp := &pb.RspUserLogin{Code: code}
		if account != nil && code == pb.ErrCode_OK {
			// 拉取用户数据
			us := &user.User{}
			us, code = s.getUser(account.ID)
			if code == pb.ErrCode_OK {
				rsp.UserId = us.ID
				rsp.Token, _ = generateToken(account.ID, account.Username)
				userId = rsp.UserId
			} else {
				rsp.Code = code
			}
		}
		topic := service.TopicEx(iMsg.ServiceName)
		s.SendServiceMsgByTopic(topic, iMsg.ConnId, userId, int32(pb.MsgId_RspUserLoginId), rsp)

		if account != nil && account.ID > 0 {
			loginLog := &user.UserLoginLog{
				AccountID:   account.ID,
				LoginIP:     req.Ip,
				LoginTime:   time.Now(),
				DeviceInfo:  req.DeviceId,
				LoginResult: code == pb.ErrCode_OK,
				FailReason:  code.String(),
			}
			switch code {
			case pb.ErrCode_LoginUserOrPwdErr, pb.ErrCode_OK:
				rpcMsg := ipb.MakeRpcMsg(rpc.LogUserAccountLogin, 0, loginLog)
				ksync.GoSafe(func() {
					_, _ = s.CallByTopic(service.RpcTopicEx(node.Name), timeout, rpcMsg)
				}, nil)

			}
		}

	}, nil)
}
