package weixinapi

import (
	"bytes"
	"encoding/json"
	"errors"
	"git.rosy.net.cn/baseapi/utils"
	"git.rosy.net.cn/jx-callback/globals"
)

type SNSTokenInfo struct {
	AccessToken  string `json:"access_token"`
	ExpiresIn    int    `json:"expires_in"`
	RefreshToken string `json:"refresh_token"`
	OpenID       string `json:"openid"`
	Scope        string `json:"scope"`
}

type SNSUserInfo struct {
	OpenID     string      `json:"openid"`
	NickName   string      `json:"nickname"`
	Sex        int         `json:"sex"`
	Province   string      `json:"province"`
	City       string      `json:"city"`
	Country    string      `json:"country"`
	HeadImgURL string      `json:"headimgurl"`
	Privilege  interface{} `json:"privilege"`
	UnionID    string      `json:"unionid"`
}

type SessionInfo struct {
	OpenID     string `json:"openid"`
	SessionKey string `json:"session_key"`
	UnionID    string `json:"unionid"`
}

type MiniUserInfo struct {
	OpenID          string `json:"openId"`
	NickName        string `json:"nickName"`
	Gender          int    `json:"gender"`
	Language        string `json:"language"`
	City            string `json:"city"`
	PhoneNumber     string `json:"phoneNumber"`
	PurePhoneNumber string `json:"purePhoneNumber"`
	Province        string `json:"province"`
	Country         string `json:"country"`
	CountryCode     string `json:"countryCode"`
	AvatarURL       string `json:"avatarUrl"`
	UnionID         string `json:"unionId"`
	Watermark       struct {
		Timestamp int    `json:"timestamp"`
		Appid     string `json:"appid"`
	} `json:"watermark"`
}

type GetUserPhone struct {
	ErrCode   int64      `json:"errcode"`
	ErrMsg    string     `json:"errmsg"`
	PhoneInfo *UserPhone `json:"phone_info"`
}

// UserPhone 微信小程序解密后 用户手机号结构体
type UserPhone struct {
	PhoneNumber     string         `json:"phoneNumber,omitempty"`
	PurePhoneNumber string         `json:"purePhoneNumber,omitempty"`
	CountryCode     string         `json:"countryCode,omitempty"`
	Watermark       *watermarkInfo `json:"watermark,omitempty"`
}

type watermarkInfo struct {
	Appid     string `json:"appid,omitempty"`
	Timestamp int    `json:"timestamp,omitempty"`
}

func mapData2SNSToken(result map[string]interface{}) *SNSTokenInfo {
	return &SNSTokenInfo{
		AccessToken:  utils.Interface2String(result["access_token"]),
		ExpiresIn:    int(utils.MustInterface2Int64(result["expires_in"])),
		RefreshToken: utils.Interface2String(result["refresh_token"]),
		OpenID:       utils.Interface2String(result["openid"]),
		Scope:        utils.Interface2String(result["scope"]),
	}
}

func (a *API) SNSRetrieveToken(code string) (tokenInfo *SNSTokenInfo, err error) {
	result, err := a.AccessAPI("sns/oauth2/access_token", utils.Params2Map("grant_type", "authorization_code", "code", code), "")
	if err != nil {
		globals.SugarLogger.Debugf("SNSRetrieveToken err=%v", err)
		return nil, err
	}
	globals.SugarLogger.Debugf("SNSRetrieveToken result=%s", mapData2SNSToken(result))
	return mapData2SNSToken(result), nil
}

func (a *API) SNSRefreshToken(refreshToken string) (tokenInfo *SNSTokenInfo, err error) {
	result, err := a.AccessAPI("sns/oauth2/refresh_token", utils.Params2Map("grant_type", "refresh_token", "refresh_token", refreshToken), "")
	if err != nil {
		return nil, err
	}
	return mapData2SNSToken(result), nil
}

func (a *API) SNSGetUserInfo(accessToken, openid string) (*SNSUserInfo, error) {
	result, err := a.AccessAPI("sns/userinfo", map[string]interface{}{
		"access_token": accessToken,
		"openid":       openid,
	}, "")
	if err == nil {
		retVal := &SNSUserInfo{
			OpenID:     utils.Interface2String(result["openid"]),
			NickName:   utils.Interface2String(result["nickname"]),
			Sex:        int(utils.MustInterface2Int64(result["sex"])),
			Province:   utils.Interface2String(result["province"]),
			City:       utils.Interface2String(result["city"]),
			Country:    utils.Interface2String(result["country"]),
			HeadImgURL: utils.Interface2String(result["headimgurl"]),
			Privilege:  result["privilege"],
			UnionID:    utils.Interface2String(result["unionid"]),
		}
		return retVal, nil
	}
	return nil, err
}

func (a *API) SNSIsOpenIDValid(accessToken, openid string) (bool, error) {
	_, err := a.AccessAPI("sns/auth", map[string]interface{}{
		"access_token": accessToken,
		"openid":       openid,
	}, "")
	if err == nil {
		return true, nil
	}
	return false, err
}

func (a *API) SNSCode2Session(jsCode string) (sessionInfo *SessionInfo, err error) {
	result, err := a.AccessAPI("sns/jscode2session", map[string]interface{}{
		"js_code":    jsCode,
		"grant_type": "authorization_code",
	}, "")
	if err == nil {
		return &SessionInfo{
			OpenID:     utils.Interface2String(result["openid"]),
			SessionKey: utils.Interface2String(result["session_key"]),
			UnionID:    utils.Interface2String(result["unionid"]),
		}, nil
	}
	return nil, err
}

func (a *API) SNSGetUserPhone(jsCode string) (string, error) {
	url := "wxa/business/getuserphonenumber"
	if a.token == "" {
		a.CBRetrieveToken()
	}
	bodyJson := map[string]interface{}{
		"code": jsCode,
	}

	result, err := a.AccessAPI(url, nil, string(utils.MustMarshal(bodyJson)))
	if err != nil {
		return "", err
	}
	var phoneInfo *GetUserPhone
	if err := utils.Map2StructByJson(result, &phoneInfo, false); err != nil {
		return "", err
	}

	if phoneInfo.ErrCode != 0 {
		return "", errors.New(phoneInfo.ErrMsg)
	}
	return phoneInfo.PhoneInfo.PhoneNumber, nil
}

// 获取小程序短连接CBRetrieveToken
func (a *API) MiniProgramSortLink() (string, error) {
	weChatToken := ""
	token := a.CBGetToken()
	if token == "" {
		newToken, err := a.CBRetrieveToken()
		if err != nil {
			return "", err
		}
		weChatToken = newToken.AccessToken
	} else {
		weChatToken = token
	}
	parmaJson := map[string]interface{}{
		"access_token": weChatToken,
	}

	bodyJson := map[string]interface{}{
		//"access_token ": weChatToken,
		"expire_type":     1,
		"expire_interval": 1,
	}
	body, _ := json.Marshal(bodyJson)
	result, err := a.AccessAPI("wxa/generate_urllink", parmaJson, string(body))
	if err != nil {
		return "", err
	}

	errCode, _ := result["errcode"].(json.Number).Int64()
	if errCode != 0 {
		return "", errors.New(result["errmsg"].(string))
	}

	return result["url_link"].(string), nil
}

// 待删除
func (a *API) SNSDecodeMiniProgramData(encryptedData, sessionKey, iv string) (decryptedData []byte, err error) {
	return SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
}

func SNSDecodeMiniProgramData(encryptedData, sessionKey, iv string) (decryptedData []byte, err error) {
	decodedDataList, err := utils.Base64DecodeMultiString(encryptedData, sessionKey, iv)
	if err != nil {
		return nil, err
	}
	decryptedData, err = utils.AESCBCDecpryt(decodedDataList[0], decodedDataList[1], decodedDataList[2])
	return decryptedData, err
}

func PKCSUnPadding(origData []byte) []byte {
	length := len(origData)
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

func PKCSPadding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}
