package main

import (
	"crypto/sha1"
	"errors"
	"fmt"
	"log"
	"math/rand"
	"sort"
	"strings"
	"time"
)

//Article is one item in News Message
// one such message can contains upto 10 Articles
type Article struct {
	title, description, picURL, url string
}

//BuildTextMsg Given a text message send it to wechat client
func BuildTextMsg(ToUserName string, txt string) (xml string, err error) {
	if txt == "" || ToUserName == "" {
		err = errors.New("Empty text body or Empty destination")
		xml = ""
		return
	}

	msg := fmt.Sprintf(txtMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), txt)
	e := Encode(msg)
	xml, _, _, _ = signMsg(e)
	return
}

//BuildKFTransferAnyOneMsg  Transfer to anyone
func BuildKFTransferAnyOneMsg(toUser string) (xml string, err error) {
	return BuildKFTransferMsg(toUser, "")

}

//BuildKFTransferMsg  Transfer a message to specific kf
func BuildKFTransferMsg(toUser, kf string) (xml string, err error) {
	msg := buildKfForwardMsg(toUser, kf)
	e := Encode(msg)
	xml, _, _, _ = signMsg(e)
	return
}

//BuildLocationMsg doesn't work for build location message
// func BuildLocationMsg(long, lat, precision float64, ToUserName string) (xml string) {
// 	msg := buildLocationMsg()
// 	e := Encode(msg)
// 	xml, _, _, _ = signMsg(e)
// 	return
// }

func signMsg(content string) (xml string, timestamp int32, nonce int32, signature string) {
	timestamp = int32(time.Now().Unix())
	nonce = rand.Int31()

	strTimestamp := fmt.Sprintf("%d", timestamp)
	strNonce := fmt.Sprintf("%d", nonce)
	signature = getSignature(APIConfig.Token, strTimestamp, strNonce, content)
	xml = "<xml>" +
		"<Encrypt>" + content + "</Encrypt>" +
		"<MsgSignature>" + signature + "</MsgSignature>" +
		"<TimeStamp>" + strTimestamp + "</TimeStamp>" +
		"<Nonce>" + strNonce + "</Nonce>" +
		"</xml>"
	return
}

func getSignature(token string, timestamp string, nonce string, content string) (signature string) {
	strs := []string{token, timestamp, nonce, content}
	sort.Strings(strs)
	s := strings.Join(strs, "")
	h := sha1.New()
	h.Write([]byte(s))
	signature = fmt.Sprintf("%x", h.Sum(nil))
	return
}

func buildTxtMsg(ToUserName, content string) (msg string) {
	msg = fmt.Sprintf(txtMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), content)
	return
}
func txtMsgTemplate() string {
	return `<xml>
 <ToUserName><![CDATA[%s]]></ToUserName>
 <FromUserName><![CDATA[%s]]></FromUserName>
 <CreateTime>%d</CreateTime>
 <MsgType><![CDATA[text]]></MsgType>
 <Content><![CDATA[%s]]></Content>
 </xml>`
}

//upload image to media as temp data, get mediaid and send it out
func buildUploadPicMsg(ToUserName, path string) (msg string) {

	mediaID := uploadImage(path)
	msg = buildPicMsg(ToUserName, mediaID)
	return
}

func buildPicMsg(ToUserName, mediaID string) (msg string) {
	msg = fmt.Sprintf(picMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), mediaID)
	return
}
func picMsgTemplate() string {
	return `<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%d</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA[%s]]></MediaId>
</Image>
</xml>`
}

func buildUploadVoiceMsg(ToUserName, path string) (msg string) {
	mediaID := uploadVoice(path)
	log.Println("get media id " + mediaID)
	msg = buildVoiceMsg(ToUserName, mediaID)
	return
}

func buildVoiceMsg(ToUserName, mediaID string) (msg string) {
	msg = fmt.Sprintf(voiceMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), mediaID)
	return
}
func voiceMsgTemplate() string {
	return `<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%d</CreateTime>
<MsgType><![CDATA[voice]]></MsgType>
<Voice>
<MediaId><![CDATA[%s]]></MediaId>
</Voice>
</xml>`
}

func buildVideoMsg(ToUserName, mediaID, title, description string) (msg string) {
	msg = fmt.Sprintf(videoMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), mediaID, title, description)
	return
}
func videoMsgTemplate() string {
	return `<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%d</CreateTime>
<MsgType><![CDATA[video]]></MsgType>
<Video>
<MediaId><![CDATA[%s]]></MediaId>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
</Video> 
</xml>`
}

func buildSampleMusicMsg(ToUserName string) (msg string) {
	thumbID := "AxEDlSNwJcs_0KnyiGnpAYiB1-sjITosWkU3VFsj62KuCyTQO-Fh1UH8d-pBmY1K"
	thumbID = "JZoNKZr9gzaI5ELBnFUljujiBfIwr4CtXHkZtQMjm-sLVD5PGOU_uvsaF3oNNFjp"
	thumbID = "5dlAsVZ8znWBuGLTjAFM8mIqapHiI0Cmazsvx4TmbsQXZk73RZz8AVnbZp6oSJZn" //jpg 200x200
	thumbID = "e2iNEiSxCX5TV1WbFd0TQJsw84YtISnam2Q_qEXDdT4"                      //永久素材的 ID
	url := "http://www.youtubeinmp3.com/download/get/?i=vNIuJKoAE46uz2RggRaKGFqQUVAqd0Td&e=92&progressType=button&color=008000"
	url = "http://agobe.yt-downloader.org/download.php?id=d7be28d3a1fafa69d7e464edb8186226"
	url = "http://www.sample-videos.com/audio/mp3/india-national-anthem.mp3"
	url = "http://google.com/"
	url = "http://m.creaders.net/travel/2017/05/11/1823175.html"
	url = "https://biukop.com.au/music.mp3" //real mp3
	//url = "https://doc.biukop.com.au/angular2/#/pages/dashboard"
	//url = "http://mp.weixin.qq.com/s/Jo7rmlMZa_iO97eckWIzFg"
	msg = buildMusicMsg(ToUserName, thumbID, "音乐标杆出", "测试音乐缩略土月卡其", url, url)
	return
}

func buildMusicMsg(ToUserName, ThumbMediaID, title, description, url, hqURL string) (msg string) {
	msg = fmt.Sprintf(musicMsgTemplate(),
		ToUserName,
		APIConfig.PublicAccountID,
		int32(time.Now().Unix()),
		title,
		description,
		url,
		hqURL,
		ThumbMediaID)
	return
}
func musicMsgTemplate() string {
	return `<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%d</CreateTime>
<MsgType><![CDATA[music]]></MsgType>
<Music>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<MusicUrl><![CDATA%s]]></MusicUrl>
<HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
<ThumbMediaId><![CDATA[%s]]></ThumbMediaId>
</Music>
</xml>`
}

func buildSampleArticleMsg(ToUserName string) (msg string) {
	art := Article{}
	art.title = "标题描述很长，不知道多少汉字"
	art.description = "f;alsfjl;dsajfls;ajfl;sajl;fjdsal;fs"
	art.picURL = "http://placehold.it/360x200"
	art.url = "http://doc.biukop.com.au/"

	articles := []Article{}
	articles = append(articles, art)
	articles = append(articles, art)
	msg = buildNewsMsg(ToUserName, "标题", "描述", articles)
	return
}

func buildNewsMsg(ToUserName, title, description string, articles []Article) (msg string) {
	count := 0
	items := []string{}
	for _, a := range articles {
		if count >= 8 {
			err := errors.New("too many articles, only take first 8")
			log.Println(err)
			break
		}
		s := buildArticleItem(a)
		items = append(items, s)
		count++
	}
	strItems := strings.Join(items, "")

	msg = fmt.Sprintf(newsMsgTemplate(),
		ToUserName,
		APIConfig.PublicAccountID,
		int32(time.Now().Unix()),
		count,
		strItems)
	return
}

func buildArticleItem(item Article) (article string) {
	template := `<item>
<Title><![CDATA[%s]]></Title> 
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>
`
	article = fmt.Sprintf(template,
		item.title, item.description, item.picURL, item.url)
	return article
}

func newsMsgTemplate() string {
	return `<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%d</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>%d</ArticleCount>
<Articles>
%s
</Articles>
</xml>`
}

// func buildLocationMsg() string {
// 	template := `<xml>
// <ToUserName><![CDATA[oUN420bxqFqlx0ZQHciUOesZO3PE]]></ToUserName>
// <FromUserName><![CDATA[gh_f09231355c68]]></FromUserName>
// <CreateTime>1494124221</CreateTime>
// <MsgType><![CDATA[location]]></MsgType>
// <Location_X>23.134521</Location_X>
// <Location_Y>113.358803</Location_Y>
// <Scale>20</Scale>
// <Label><![CDATA[位置信息]]></Label>
// </xml> `
// 	return template
// }

func buildKfForwardMsg(toUser string, kf string) (msg string) {
	//转发信息到任意客服
	template := `<xml>s
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%d</CreateTime>
<MsgType><![CDATA[transfer_customer_service]]></MsgType>
 </xml>`

	//发送信息指定客服人员
	templateKF := ` <xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%d</CreateTime>
<MsgType><![CDATA[transfer_customer_service]]></MsgType>
<TransInfo>
	<KfAccount><![CDATA[%s]]></KfAccount>
</TransInfo>
</xml>`

	if kf == "" {
		msg = fmt.Sprintf(template, toUser, APIConfig.PublicAccountID, time.Now().Unix())
	} else {
		msg = fmt.Sprintf(templateKF, toUser, APIConfig.PublicAccountID, time.Now().Unix(), kf)
	}

	return
}
