package server

import (
	"fmt"
	"sdk_api/constant"
	apiModel "sdk_api/model/api"
	"sdk_api/util"
	"strings"

	"github.com/ethereum/go-ethereum/accounts"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/gin-gonic/gin"
	"github.com/tidwall/gjson"
)

func checkUser(c *gin.Context) {
	req := &apiModel.CheckUserRequest{}
	if err := c.ShouldBindJSON(req); err != nil {
		c.JSON(200, withError(constant.InvalidParam))
		return
	}
	switch req.Platform {
	case constant.PlatformTelegram:
		var ok bool
		var userId string
		var botId string
		for _, token := range conf.TGBot.Tokens {
			ok, botId, userId = util.VerifyInitData(req.InitData, token)
			if ok {
				break
			}
		}
		if !ok {
			c.JSON(200, withError("invalid initData"))
			return
		}
		dbId := fmt.Sprintf("%s:%s", botId, userId)
		ok, uid, keystore, err := srv.CheckUser(constant.PlatformTelegram, dbId)
		if err != nil {
			c.JSON(200, withError(constant.InternalError))
			return
		}

		token := util.GenerateJWT(uid, constant.PlatformTelegram, dbId)

		resp := &apiModel.CheckUserResponse{
			IsNewUser: !ok,
			Keystore:  keystore,
			Token:     token,
		}
		c.JSON(200, withSuccess(resp))
		return

	case constant.PlatformFingerprint:
		userId := req.VisitorID

		ok, uid, keystore, err := srv.CheckUser(constant.PlatformFingerprint, userId)
		if err != nil {
			c.JSON(200, withError(constant.InternalError))
			return
		}

		token := util.GenerateJWT(uid, constant.PlatformFingerprint, userId)

		resp := &apiModel.CheckUserResponse{
			IsNewUser: !ok,
			Keystore:  keystore,
			Token:     token,
		}

		c.JSON(200, withSuccess(resp))

	default:
		c.JSON(200, withError(constant.UnsupportedPlatform))
		return
	}
}

func createUser(c *gin.Context) {
	req := &apiModel.CreateUserRequest{}
	if err := c.ShouldBindJSON(req); err != nil {
		c.JSON(200, withError(constant.InvalidParam))
		return
	}

	uid := c.GetString("jwt-uid")

	address := gjson.Get(req.Keystore, "address").String()
	binSignature, err := hexutil.Decode(req.Signature)
	if err != nil || len(binSignature) < 65 {
		c.JSON(200, withError("invalid signature"))
		return
	}
	binSignature[64] -= 27
	ecdsaPub, err := crypto.SigToPub(accounts.TextHash([]byte(req.Keystore)), binSignature)
	if err != nil {
		c.JSON(200, withError("invalid signature"))
		return
	}
	addr := crypto.PubkeyToAddress(*ecdsaPub)
	if strings.ToLower(addr.Hex()[2:]) != address {
		c.JSON(200, withError("invalid signature"))
		return
	}

	ok, err := srv.SetKeystore(uid, strings.ToLower(addr.Hex()), req.Keystore)
	if err != nil {
		c.JSON(200, withError(constant.InternalError))
		return
	}

	if !ok {
		c.JSON(200, withError("keystore already exist"))
		return
	}
	srv.AONSendGas(addr.Hex())
	c.JSON(200, withSuccess(""))
}

func login(c *gin.Context) {
	req := &apiModel.LoginRequest{}
	if err := c.ShouldBindJSON(req); err != nil {
		c.JSON(200, withError(constant.InvalidParam))
		return
	}
	var platformId string
	switch req.Platform {
	case constant.PlatformTelegram:
		var ok bool
		var userId string
		var botId string
		for _, token := range conf.TGBot.Tokens {
			ok, botId, userId = util.VerifyInitData(req.InitData, token)
			if ok {
				break
			}
		}
		if !ok {
			c.JSON(200, withError("invalid initData"))
			return
		}
		platformId = fmt.Sprintf("%s:%s", botId, userId)
	case constant.PlatformFingerprint:
		if len(req.VisitorID) <= 10 {
			c.JSON(200, withError(constant.InvalidParam))
			return
		}
		platformId = req.VisitorID
	default:
		c.JSON(200, withError(constant.UnsupportedPlatform))
		return
	}
	// 检查签名是否为keystore中的地址
	address := gjson.Get(req.Keystore, "address").String()
	binSignature, err := hexutil.Decode(req.Signature)
	if err != nil || len(binSignature) < 65 {
		c.JSON(200, withError("invalid signature"))
		return
	}
	binSignature[64] -= 27
	ecdsaPub, err := crypto.SigToPub(accounts.TextHash([]byte(req.Keystore)), binSignature)
	if err != nil {
		c.JSON(200, withError("invalid signature"))
		return
	}
	addr := crypto.PubkeyToAddress(*ecdsaPub)
	if strings.ToLower(addr.Hex()[2:]) != address {
		c.JSON(200, withError("invalid signature"))
		return
	}

	isExistKeystore, uid, keystore, err := srv.CheckUser(req.Platform, platformId)
	if err != nil {
		c.JSON(200, withError(constant.InternalError))
		return
	}

	token := util.GenerateJWT(uid, req.Platform, platformId)

	resp := &apiModel.CheckUserResponse{
		IsNewUser: !isExistKeystore,
		Keystore:  keystore,
		Token:     token,
		Uid:       uid,
	}

	if !isExistKeystore {
		_, err = srv.SetKeystore(uid, address, req.Keystore)
		if err != nil {
			c.JSON(200, withError(constant.InternalError))
			return
		}

		resp.Keystore = req.Keystore
	}
	taskId, err := srv.AONServerLogin(address, req.UserId, req.InviterId)
	if err != nil {
		c.JSON(200, withError(constant.InternalError))
		return
	}
	resp.TaskId = taskId
	c.JSON(200, withSuccess(resp))
	return
}

func loginV2(c *gin.Context) {
	req := &apiModel.LoginRequest{}
	if err := c.ShouldBindJSON(req); err != nil {
		c.JSON(200, withError(constant.InvalidParam))
		return
	}
	var platformId string
	switch req.Platform {
	case constant.PlatformTelegram:
		var ok bool
		var userId string
		var botId string
		for _, token := range conf.TGBot.Tokens {
			ok, botId, userId = util.VerifyInitData(req.InitData, token)
			if ok {
				break
			}
		}
		if !ok {
			c.JSON(200, withError("invalid initData"))
			return
		}
		_ = botId
		// platformId = fmt.Sprintf("%s:%s", botId, userId)
		platformId = fmt.Sprintf("v2:%s", userId)
	case constant.PlatformFingerprint:
		if len(req.VisitorID) <= 10 {
			c.JSON(200, withError(constant.InvalidParam))
			return
		}
		platformId = req.VisitorID
	default:
		c.JSON(200, withError(constant.UnsupportedPlatform))
		return
	}
	// 检查签名是否为keystore中的地址
	address := gjson.Get(req.Keystore, "address").String()
	binSignature, err := hexutil.Decode(req.Signature)
	if err != nil || len(binSignature) < 65 {
		c.JSON(200, withError("invalid signature"))
		return
	}
	binSignature[64] -= 27
	ecdsaPub, err := crypto.SigToPub(accounts.TextHash([]byte(req.Keystore)), binSignature)
	if err != nil {
		c.JSON(200, withError("invalid signature"))
		return
	}
	addr := crypto.PubkeyToAddress(*ecdsaPub)
	if strings.ToLower(addr.Hex()[2:]) != address {
		c.JSON(200, withError("invalid signature"))
		return
	}

	isExistKeystore, uid, keystore, err := srv.CheckUser(req.Platform, platformId)
	if err != nil {
		c.JSON(200, withError(constant.InternalError))
		return
	}

	token := util.GenerateJWT(uid, req.Platform, platformId)

	resp := &apiModel.CheckUserResponse{
		IsNewUser: !isExistKeystore,
		Keystore:  keystore,
		Token:     token,
		Uid:       uid,
	}

	if !isExistKeystore {
		_, err = srv.SetKeystore(uid, address, req.Keystore)
		if err != nil {
			c.JSON(200, withError(constant.InternalError))
			return
		}

		resp.Keystore = req.Keystore
	}
	taskId, err := srv.AONServerLogin(address, req.UserId, req.InviterId)
	if err != nil {
		c.JSON(200, withError(constant.InternalError))
		return
	}
	resp.TaskId = taskId
	c.JSON(200, withSuccess(resp))
	return
}