package umeng

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/astaxie/beego/httplib"
	"io/ioutil"
	"net/http"
	"openapi/pkg/infrastructure/push"
	"strings"
	"time"
)

var (
	Host       = "http://msg.umeng.com"
	ApiSend    = "/api/send"
	UploadPath = "/upload"
)

var FiledErrorFormat = "缺少字段:%v"
var FiledErrorFormatFunc = func(filed string) error {
	return fmt.Errorf(FiledErrorFormat, filed)
}

const (
	AppKey         = "appkey"
	Timestamp      = "timestamp"
	Type           = "type"
	ProductionMode = "production_mode"
	DeviceTokens   = "device_tokens"
	Payload        = "payload"
	Policy         = "policy"
	Description    = "description"

	DisplayType = "displayType"
	Body        = "body"
	Ticker      = "ticker" // 必填,通知栏提示文字
	Title       = "title"  // 必填,通知标题
	Text        = "text"   //必填,通知文字描述
	/*
		// 可选,默认为"go_app",值可以为:
		//   "go_app": 打开应用
		//   "go_url": 跳转到URL
		//   "go_activity": 打开特定的activity
		//   "go_custom": 用户自定义内容。
	*/
	AfterOpen = "after_open"
	Extra     = "extra"
)

const (
	Message      = "message"
	Notification = "notification"
)
const (
	ExpireSpan = time.Second * 60 * 60 * 24
)

type SetPayload func(msg *UnicastMsg, option map[string]interface{}) error

type UmengNotification struct {
	Auth    *Auth
	Request *httplib.BeegoHTTPRequest
}

func (notify *UmengNotification) Init(options ...push.Option) error {
	return nil
}
func (notify *UmengNotification) Send(option map[string]interface{}) error {
	var (
		setPayload SetPayload = SetAndroidPayload
		body       []byte
		err        error
		httpRsp    *http.Response
		ret        = make(map[string]interface{})
		data       []byte
	)
	if option["DeviceType"].(int) == 1 {
		setPayload = SetAndroidPayload
	}
	if body, err = notify.PostBody(option, setPayload); err != nil {
		return err
	}
	notify.Request = httplib.Post(notify.Url(ApiSend, body))
	notify.Request.Body(body)

	if httpRsp, err = notify.Request.DoRequest(); err != nil {
		return err
	}
	data, err = ioutil.ReadAll(httpRsp.Body)
	defer httpRsp.Body.Close()
	if err != nil {
		return err
	}
	if err = json.Unmarshal(data, &ret); err != nil {
		return err
	}
	if status, ok := ret["ret"]; ok {
		if strings.EqualFold(fmt.Sprintf("%v", status), "SUCCESS") {
			return nil
		}
		return fmt.Errorf("response:%v fail", ret)
	}
	return fmt.Errorf("response:%v invaild", ret)
}
func (notify *UmengNotification) PostBody(option map[string]interface{}, setPayload SetPayload) (body []byte, err error) {
	var postData = new(UnicastMsg)
	postData.AppKey = notify.Auth.AppKey
	postData.Timestamp = fmt.Sprintf("%v", time.Now().Unix())
	postData.ProductionMode = fmt.Sprintf("%v", true)
	postData.Type = fmt.Sprintf("%v", option[Type])
	postData.DeviceTokens = fmt.Sprintf("%v", option[DeviceTokens])
	postData.Policy = MsgPolicy{ExpireTime: time.Now().Add(ExpireSpan).Format("2006-01-02 15:04:05")}
	if err = setPayload(postData, option); err != nil {
		return
	}
	postData.Description = fmt.Sprintf("%v", option[Title])
	if body, err = json.Marshal(postData); err != nil {
		return
	}
	return
}
func (notify *UmengNotification) Url(method string, body []byte) string {
	var url string = fmt.Sprintf("%v%v", Host, method)
	sign := fmt.Sprintf("%x", md5.Sum([]byte("POST"+url+string(body)+notify.Auth.AppMasterSecret)))
	url = fmt.Sprintf("%v?sign=%v", url, sign)
	return url
}

type UnicastMsg struct {
	AppKey         string     `json:"appkey"`
	Timestamp      string     `json:"timestamp"`
	Type           string     `json:"type"` //发送类型 单播 列播...
	ProductionMode string     `json:"production_mode"`
	DeviceTokens   string     `json:"device_tokens"`
	Payload        MsgPayload `json:"payload"`
	Policy         MsgPolicy  `json:"policy"`
	Description    string     `json:"description"`
}
type MsgPayload map[string]interface{}
type MsgPolicy struct {
	ExpireTime string `json:"expire_time"`
}

//设置payload
func SetAndroidPayload(msg *UnicastMsg, option map[string]interface{}) error {
	msg.Payload = make(map[string]interface{})
	var (
		displayType string
		ok          bool
	)
	if _, ok = option[DisplayType]; !ok {
		return FiledErrorFormatFunc(DisplayType)
	}
	displayType = option[DisplayType].(string)
	switch displayType {
	case Message:
		break
	case Notification:
		var payloadBody = make(map[string]interface{})
		//if _,ok =option[Title];!ok{
		//	return FiledErrorFormatFunc(Title)
		//}
		//if _,ok =option[Text];!ok{
		//	return FiledErrorFormatFunc(Text)
		//}
		//if _,ok =option[Extra];ok{
		//	payloadBody[Extra]=option[Extra]
		//}
		payloadBody[Ticker] = option[Title]
		payloadBody[Title] = option[Title]
		payloadBody[Text] = option[Text]
		payloadBody[AfterOpen] = "go_app"
		msg.Payload[Body] = payloadBody
		break
	default:
		return FiledErrorFormatFunc(DisplayType)
		break
	}
	return nil
}