package auth

import (
	"encoding/json"
	"eta/eta_mini_ht_api/models"
	"fmt"
	"github.com/silenceper/wechat/v2"
	"github.com/silenceper/wechat/v2/cache"
	"gorm.io/gorm"
	"io"
	"net/http"
	"time"

	"github.com/silenceper/wechat/v2/credential"
	"github.com/silenceper/wechat/v2/officialaccount"
	"github.com/silenceper/wechat/v2/officialaccount/config"
	"github.com/silenceper/wechat/v2/officialaccount/js"
	"github.com/silenceper/wechat/v2/officialaccount/user"
)

var (
	WxAppId     string
	WxAppSecret string
)

// 海通公众号配置
const (
	HT_WX_APPID      = "wxf0dfb65c325fee66"
	HT_WX_APP_SECRET = "4f2a6c4f9b0a9dee08d1b3b316f33228"
	HT_WX_ID         = "gh_b2f5b115ec8d"
)

type WechatAccessToken struct {
}

var DefaultKey = "zcmRedis"

// GetAccessToken 获取accessToken
func (wechat WechatAccessToken) GetAccessToken() (accessToken string, err error) {
	wxToken, err := models.GetWxTokenById()

	var isRegister bool
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			isRegister = true
		} else {
			return
		}
	}
	if isRegister {
		tmpAccessToken, expires, tmpErr := getTokenFromServer(HT_WX_APPID, HT_WX_APP_SECRET)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		token := new(models.WxToken)
		token.AccessToken = tmpAccessToken
		token.ExpiresIn = expires
		err = models.RegisterWxToken(token)
		if err != nil {
			return "", err
		}
		accessToken = tmpAccessToken
		return
	}

	//如果300s就要过期了，那么就去刷新accessToken
	if wxToken.ExpiresIn < time.Now().Unix()+300 {
		tmpAccessToken, expires, tmpErr := getTokenFromServer(HT_WX_APPID, HT_WX_APP_SECRET)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		expiresIn := time.Now().Unix() + expires - 600 //快过期前10分钟就刷新掉
		models.UpdateWxToken(tmpAccessToken, expiresIn)
		accessToken = tmpAccessToken
	}
	accessToken = wxToken.AccessToken
	return
}

// getTokenFromServer 服务端获取accessToken
func getTokenFromServer(appid, wxSecret string) (accessToken string, expires int64, err error) {
	apiUrl := "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"
	resAccessToken, err := credential.GetTokenFromServer(fmt.Sprintf(apiUrl, appid, wxSecret))
	if err != nil {
		return
	}

	expires = resAccessToken.ExpiresIn
	accessToken = resAccessToken.AccessToken
	return
}

func GetWxChat() (officialAccount *officialaccount.OfficialAccount) {
	wc := wechat.NewWechat()
	memory := cache.NewMemory()
	conf := &config.Config{
		AppID:          HT_WX_APPID,
		AppSecret:      HT_WX_APP_SECRET,
		Token:          "",
		EncodingAESKey: "",
		Cache:          memory,
	}
	officialAccount = wc.GetOfficialAccount(conf)
	wechatAccessToken := &WechatAccessToken{}
	officialAccount.SetAccessTokenHandle(wechatAccessToken)
	return
}

// GetUserInfo 获取微信用户详情
func GetUserInfo(openid string) (userInfo *user.Info, err error) {
	wechatClient := GetWxChat()
	userClient := wechatClient.GetUser()
	userInfo, err = userClient.GetUserInfo(openid)
	return
}

// GetJsConfig 获取公众号jsConfig
func GetJsConfig(signUrl string) (jsConf *js.Config, err error) {
	wechatClient := GetWxChat()
	j := wechatClient.GetJs()
	jsConf, err = j.GetConfig(signUrl)
	return
}

type WxUserInfo struct {
	OpenId       string `json:"openid"`
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	Scope        string `json:"scope"`
	ErrCode      int
	ErrMsg       string
}

func GetWxUserInfo(code string) (info *WxUserInfo, err error) {
	httpUrl := `https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code`

	httpUrl = fmt.Sprintf(httpUrl, HT_WX_APPID, HT_WX_APP_SECRET, code)

	client := http.Client{}
	wxReq, err := http.NewRequest("GET", httpUrl, nil)
	if err != nil {
		return
	}
	response, err := client.Do(wxReq)
	if err != nil {
		return
	}
	defer response.Body.Close()
	body, err := io.ReadAll(response.Body)
	if err != nil {
		return
	}
	if err = json.Unmarshal(body, &info); err != nil {
		return
	}
	return
}

// GetUserInfo 获取微信用户详情
func GetWxUserDetail(openid string) (userInfo *user.Info, err error) {
	wechatClient := GetWxChat()
	userClient := wechatClient.GetUser()
	userInfo, err = userClient.GetUserInfo(openid)
	return
}
