package getui

import (
	"crypto/sha256"
	"fmt"
	"github.com/astaxie/beego/httplib"
	"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
	"openapi/internal/push"
	"openapi/internal/utils"
	"strings"
	"sync"
	"time"
)

var (
	host       = "https://restapi.getui.com"
	pushSingle = "push_single"
	authSign   = "auth_sign "
)

var (
	authtoken  = ""
	expire     time.Time
	authMux    sync.RWMutex
	expireSpan = time.Second * 3600 * 6
)

type GetuiNotification struct {
	Options *push.Options
	Request *httplib.BeegoHTTPRequest
}

func (notify *GetuiNotification) Init(options ...push.Option) error {
	notify.Options = &push.Options{}
	for _, o := range options {
		o(notify.Options)
	}
	return nil
}
func (notify *GetuiNotification) Send(option map[string]interface{}) error {
	token, err := notify.GetAuthToken()
	if err != nil {
		return err
	}

	var (
		result *Result
		url    = notify.Url(notify.Options.AppId, pushSingle)
	)
	notify.Request = httplib.Post(url)
	notify.Request.Header("authtoken", token)
	notify.Request.JSONBody(notify.Message())
	if err = notify.Request.ToJSON(&result); err != nil {
		return err
	}
	notify.print(url, notify.Message(), result, result)
	if err = handleResult(url, result); err != nil {
		return err
	}
	return nil
}
func (notify *GetuiNotification) Message() interface{} {
	//TODO:默认通知模板
	m := NewNotificationTemplate(notify.Options)
	return m
}
func (notify *GetuiNotification) Url(param string, method string) string {
	return fmt.Sprintf("%v/v1/%v/%v", host, param, method)
}
func (notify *GetuiNotification) GetAuthToken() (token string, err error) {
	if authtoken != "" && expire.Unix() > time.Now().Unix() {
		token = authtoken
		return
	}

	authMux.Lock()
	defer authMux.Unlock()
	url := notify.Url(notify.Options.AppId, authSign)
	notify.Request = httplib.Post(strings.TrimSpace(url))
	req := &AuthSignRequest{
		Timestamp: fmt.Sprintf("%v", time.Now().Unix()*1000), //"1589797286000",//
		AppKey:    notify.Options.AppKey,
	}
	req.Sign = sign(req.AppKey, req.Timestamp, notify.Options.AppMasterSecret)
	_, err = notify.Request.JSONBody(req)
	if err != nil {
		return
	}
	var rsp *AuthSignResponse
	err = notify.Request.ToJSON(&rsp)
	notify.print(url, req, rsp, rsp.Result)
	if err != nil {
		return
	}
	if err = handleResult(url, rsp.Result); err != nil {
		return
	}
	authtoken = rsp.AuthToken
	token = rsp.AuthToken
	expire = time.Now().Add(expireSpan)
	return
}
func handleResult(url string, result *Result) (err error) {
	if strings.ToLower(result.Result) == "ok" {
		return
	}
	err = fmt.Errorf("grequest fail,url:%v error:%v", url, result.Result)
	return err
}
func sign(appkey, timestamp, mastersecret string) string {
	sha := sha256.New()
	sha.Write([]byte(appkey + timestamp + mastersecret))
	return fmt.Sprintf("%x", sha.Sum(nil))
}
func (notify *GetuiNotification) print(url string, v interface{}, rsp interface{}, result *Result) {
	if !notify.Options.DebugModule {
		return
	}
	log.Error(fmt.Sprintf("【个推】 url:%v \n request:%v \n response:%v 结果:%v", url, utils.JsonAssertString(v), utils.JsonAssertString(rsp), result.Result))
}