package wechat

import (
	"encoding/json"
	"eta/eta_mini_ht_api/common/component/config"
	logger "eta/eta_mini_ht_api/common/component/log"
	"eta/eta_mini_ht_api/common/component/wechat/we_http"
	"eta/eta_mini_ht_api/common/contants"
	"eta/eta_mini_ht_api/common/exception"
	"eta/eta_mini_ht_api/common/utils/client"
	"fmt"
	"io"
	"net/url"
	"sync"
)

const (
	baseURL = "https://api.weixin.qq.com"
	codeAPI = "/sns/jscode2session"
)
const (
// WeChatServerError 微信服务器错误时返回返回消息

)

var (
	wechatClient *Client
	once         sync.Once
)

type Client struct {
	// HTTP请求客户端
	client *client.HttpClient
	// 小程序后台配置: 小程序ID
	appid string
	// 小程序后台配置: 小程序密钥
	secret string
}

func GetInstance() *Client {
	once.Do(func() {
		wechatConf, ok := config.GetConfig(contants.WECHAT).(*config.WechatConfig)
		if !ok {
			// 处理错误情况,比如记录日志或返回错误信息
			logger.Info("加载wechat配置失败")
			return // 或者采取其他适当的错误处理措施
		}
		// 默认配置
		wechatClient = NewClient(wechatConf.GetAppid(), wechatConf.GetSecret(), WithHttpClient(client.DefaultClient()))
	})
	return wechatClient
}

// AccessTokenGetter 用户自定义获取access_token的方法
type AccessTokenGetter func(appid, secret string) (token string, expireIn uint)

// NewClient 初始化客户端并用自定义配置替换默认配置
func NewClient(appid, secret string, opts ...func(*Client)) *Client {
	cli := &Client{
		appid:  appid,
		secret: secret,
	}
	// 执行额外的配置函数
	for _, fn := range opts {
		fn(cli)
	}
	return cli
}

// WithHttpClient 自定义 HTTP Client
func WithHttpClient(hc *client.HttpClient) func(*Client) {
	return func(cli *Client) {
		cli.client = hc
	}
}

type loginResponse struct {
	we_http.BaseResponse
	we_http.LoginResponse
}

// Login 小程序登录
func (cli *Client) Login(code string) (wxUser WxUser, err error) {
	if code == "" {
		err = exception.New(exception.WeChatCodeEmpty)
		return
	}
	api, err := code2url(cli.appid, cli.secret, code)
	if err != nil {
		err = exception.New(exception.WeChatIllegalRequest)
		return
	}
	//请求微信接口
	res, err := cli.client.Get(api)
	defer func(Body io.ReadCloser) {
		Body.Close()
	}(res.Body)
	if err != nil || res.StatusCode != 200 {
		logger.Error("获取微信用户信息失败:%v", res.Status)
		err = exception.New(exception.WeChatServerError)
		return
	}
	var data loginResponse
	err = json.NewDecoder(res.Body).Decode(&data)
	if err != nil {
		logger.Error("解析微信应答失败:%v", err)
		err = exception.New(exception.WeChatResponseError)
		return
	}

	fmt.Println(data)

	if data.Errcode != 0 {
		logger.Error("获取用户信息失败:%v", data.Errmsg)
		err = exception.New(exception.WechatUserInfoFailed)
		return
	}
	wxUser = WxUser{
		OpenId:  data.LoginResponse.OpenID,
		UnionId: data.LoginResponse.UnionID,
	}
	return
}

type WxUser struct {
	OpenId  string
	UnionId string
}

// 拼接 获取 session_key 的 URL
func code2url(appID, secret, code string) (string, error) {

	url, err := url.Parse(baseURL + codeAPI)
	if err != nil {
		return "", err
	}

	query := url.Query()

	query.Set("appid", appID)
	query.Set("secret", secret)
	query.Set("js_code", code)
	query.Set("grant_type", "authorization_code")

	url.RawQuery = query.Encode()

	return url.String(), nil
}

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
}

// Login 小程序登录
func (cli *Client) GzhLogin(code string) (wxUser WxUser, err error) {
	if code == "" {
		err = exception.New(exception.WeChatCodeEmpty)
		return
	}
	api, err := code2url(cli.appid, cli.secret, code)
	if err != nil {
		err = exception.New(exception.WeChatIllegalRequest)
		return
	}
	//请求微信接口
	res, err := cli.client.Get(api)
	defer func(Body io.ReadCloser) {
		Body.Close()
	}(res.Body)
	if err != nil || res.StatusCode != 200 {
		logger.Error("获取微信用户信息失败:%v", res.Status)
		err = exception.New(exception.WeChatServerError)
		return
	}
	var data loginResponse
	err = json.NewDecoder(res.Body).Decode(&data)
	if err != nil {
		logger.Error("解析微信应答失败:%v", err)
		err = exception.New(exception.WeChatResponseError)
		return
	}

	fmt.Println(data)

	if data.Errcode != 0 {
		logger.Error("获取用户信息失败:%v", data.Errmsg)
		err = exception.New(exception.WechatUserInfoFailed)
		return
	}
	wxUser = WxUser{
		OpenId:  data.LoginResponse.OpenID,
		UnionId: data.LoginResponse.UnionID,
	}
	return
}