package ppos

import (
	"PPOSUtils/utils"
	"encoding/hex"
	"encoding/json"
	"errors"
	"strings"
	"time"
)

const authCodeKey = "20140924"

//NewJwt 令牌生成器
func NewJwt(jwtType int64) JwtInterface {
	switch jwtType {
	case 0: //基础类型令牌
		return NewJwtBase()
	case 1: //包含账号
		return NewJwtAccount()
	case 2: //包含了公司id+账号
		return NewJwtCompany()
	case 3: //包含了公司id+账号+...
		return NewJwtGym()
	case 4: //微信登陆
		return NewJwtWxOpen()
	case 5: //c端(微信环境)登陆后
		return NewJwtWx()
	case 6: //c端(pc环境)登陆后
		return NewJwtWx()
	case 7: //c端(第三方平台)登陆后
		return NewJwtWx()
	default:
		return NewJwtCompany()
	}
}

//NewParseJwt 令牌解析
func NewParseJwt(jwtStr string) JwtParseInterface {
	_jwt := NewJwtBase()
	_jwt.SetJwt(jwtStr)
	return _jwt
}

func ParseJwtAuthCode(authCode string) (string, error) {
	_authCode, _err := hex.DecodeString(authCode)
	if _err != nil {
		return "", errors.New("parse jwt auth code fail!")
	}
	_authStr, _err := utils.DesDecrypt(_authCode, []byte(authCodeKey))
	if _err != nil {
		return "", _err
	}
	_authSlice := strings.Split(string(_authStr), "_")
	if len(_authSlice) < 2 {
		return "", errors.New("parse jwt auth code fail!")
	}
	if time.Now().Unix() > utils.ToInt64(_authSlice[0]) {
		return "", errors.New("parse jwt auth code is overtime!")
	}
	return _authSlice[1], nil
}

type JwtParseInterface interface {
	//ParseJwt 解析令牌
	ParseJwtType() (JwtInterface, error)
}

//令牌：公共基础字段
type JwtInterface interface {
	//SetAppID ...
	SetAppID(appID int64)
	//SetMpID 设置令牌所属应用
	SetMpID(mpID int64)
	//SetJwtType 设置令牌类型
	SetJwtType(jwtType int64)
	//SetJwt 设置令牌
	SetJwt(jwtStr string)
	//GetAppID ...
	GetAppID() int64
	//GetID 获取令牌id
	GetID() int64
	//GetMpID 获取令牌所属应用
	GetMpID() int64
	//GetMpID 获取令牌类型
	GetJwtType() int64
	//GetMpID 获取令牌生成时间
	GetCt() int64
	//GetAuthCode 零时授权码
	GetAuthCode() (string, error)
	//GetMpID 生成令牌
	CreateJwt(params ...utils.Mp) (string, error)
	//GetMpID 解析令牌的扩展参数
	ParseParams() (utils.Mp, error)
}

//NewJwtAccount 令牌：账号/账号类型
func NewJwtBase() *JwtBase {
	return &JwtBase{}
}

type JwtBase struct {
	jwtStr      string
	jwtType     int64
	appID       int64
	mpID        int64
	ct          int64
	id          int64
	authCode    string
	paramsSlice []string
	paramsMp    utils.Mp
}

func (that *JwtBase) SetAppID(appID int64) {
	that.appID = appID
}

func (that *JwtBase) SetMpID(mpID int64) {
	that.mpID = mpID
}

func (that *JwtBase) SetJwtType(jwtType int64) {
	that.jwtType = jwtType
}

func (that *JwtBase) SetJwt(jwtStr string) {
	that.jwtStr = jwtStr
}

func (that *JwtBase) GetAppID() int64 {
	return that.appID
}

func (that *JwtBase) GetMpID() int64 {
	return that.mpID
}

func (that *JwtBase) GetJwtType() int64 {
	return that.jwtType
}

func (that *JwtBase) GetID() int64 {
	return that.id
}

func (that *JwtBase) GetCt() int64 {
	return that.ct
}

func (that *JwtBase) GetAuthCode() (string, error) {
	if that.authCode == "" {
		_authSlice := []string{
			utils.ToString(time.Now().Unix() + 60),
			utils.ToString(that.id),
		}
		_desStr, _err := utils.DesEncrypt([]byte(strings.Join(_authSlice, "_")), []byte(authCodeKey))
		if _err != nil {
			return "", errors.New("get auth code fail! 001" + _err.Error())
		}
		that.authCode = hex.EncodeToString(_desStr)
	}
	return that.authCode, nil
}

func (that *JwtBase) init() {
	if that.paramsMp == nil {
		that.paramsMp = utils.NewMP()
		that.paramsSlice = []string{}
	}
}

func (that *JwtBase) CreateJwt(params ...utils.Mp) (string, error) {
	that.init()
	if len(params) > 0 {
		for _k, _v := range params[0] {
			that.paramsMp.Set(_k, _v)
		}
	}
	for _, _k := range that.paramsSlice {
		if !that.paramsMp.Has(_k) {
			return "", errors.New("jwt create fail, " + _k + " must set!")
		}
	}
	//
	_params, _err := json.Marshal(that.paramsMp)
	if _err != nil {
		return "", errors.New("jwt create fail, " + _err.Error())
	}
	that.id = time.Now().UnixNano()
	that.ct = time.Now().Unix()
	_mp := map[string]string{
		"id":     utils.ToString(that.id),
		"aid":    utils.ToString(that.appID),
		"tid":    utils.ToString(that.jwtType), //jwt类型
		"mid":    utils.ToString(that.mpID),    //应用ID
		"ct":     utils.ToString(that.ct),      //当前时间戳
		"params": string(_params),              //包含扩展参数，即应用的公共参数
	}
	that.jwtStr = utils.JwtGetHStoken(utils.GetMd5String(strings.Join([]string{
		_mp["mid"],
		_mp["params"],
		utils.ToString(that.id),
	}, "_")), _mp)
	return that.jwtStr, nil
}

//ParseJwtType
func (that *JwtBase) ParseJwtType() (JwtInterface, error) {
	//
	if _err := that.paramsJwt(); _err != nil {
		return nil, _err
	}
	_jwt := NewJwt(that.jwtType)
	_jwt.SetJwt(that.jwtStr)
	return _jwt, nil
}

func (that *JwtBase) paramsJwt() error {
	that.init()
	_mp := utils.JwtParseHStoken(that.jwtStr)
	_slice := []string{
		"id",
		"aid",
		"tid",
		"mid",
		"ct",
	}
	for _, _v := range _slice {
		if _, _ok := _mp[_v]; !_ok {
			return errors.New("jwt parse fail, '" + _v + "' not found!")
		}
	}
	//fmt.Println("***********************ParseJwtType********************", _mp)
	that.id = utils.ToInt64(_mp["id"])
	that.appID = utils.ToInt64(_mp["aid"])
	that.mpID = utils.ToInt64(_mp["mid"])
	that.jwtType = utils.ToInt64(_mp["tid"])
	that.ct = utils.ToInt64(_mp["ct"])
	//
	_params, _ok := _mp["params"]
	_paramsStr := utils.ToString(_params)
	if _ok && strings.Trim(_paramsStr, " ") != "" {
		if _err := json.Unmarshal([]byte(_paramsStr), &that.paramsMp); _err != nil {
			return errors.New("jwt parse fail, " + _err.Error())
		}
	}
	return nil
}

func (that *JwtBase) ParseParams() (utils.Mp, error) {
	that.init()
	if _err := that.paramsJwt(); _err != nil {
		return nil, _err
	}
	for _, _k := range that.paramsSlice {
		if !that.paramsMp.Has(_k) {
			return nil, errors.New("jwt parse fail, " + _k + " must set!")
		}
	}
	return that.paramsMp, nil
}
