package sender

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"net/http"
	"os/exec"
	"path"
	"strings"
	"syscall"
	"time"

	"github.com/710leo/urlooker/dataobj"
	"github.com/710leo/urlooker/modules/alarm/backend"
	"github.com/710leo/urlooker/modules/alarm/cache"
	"github.com/710leo/urlooker/modules/alarm/g"
	"github.com/710leo/urlooker/modules/web/api"

	"github.com/toolkits/file"
	"github.com/toolkits/smtp"
	"github.com/toolkits/sys"
)

var (
	SmsWorkerChan    chan int
	MailWorkerChan   chan int
	WeChatWorkerChan chan int
	requestError     = errors.New("request error,check url or network")
)

const (
	// 发送消息使用导的url
	sendUrl = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="
	// 获取token使用导的url
	getToken = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid="
)

func Init() {
	workerConfig := g.Config.Worker
	SmsWorkerChan = make(chan int, workerConfig.Sms)
	MailWorkerChan = make(chan int, workerConfig.Mail)
	WeChatWorkerChan = make(chan int, workerConfig.WeChat)
}

func SendEvent(event *dataobj.Event) {
	mail := make([]string, 0)
	sms := make([]string, 0)
	weChat := make([]string, 0)
	users := getUsers(event.StrategyId)

	mailContent := BuildMail(event)
	smsContent := BuildSms(event)
	weChatContent := BuildWeChat(event)
	for _, user := range users {
		mail = append(mail, user.Email)
		sms = append(sms, user.Phone)
		weChat = append(weChat, user.Wechat)
	}

	WriteSms(sms, smsContent)
	WriteMail(mail, smsContent, mailContent)
	WriteWeChat(weChat, weChatContent)
}

func sendSms(phone string, sms string) {
	defer func() {
		<-SmsWorkerChan
	}()

	smsShell := path.Join(file.SelfDir(), "script", "sms.sh")
	if !file.IsExist(smsShell) {
		log.Printf("%s not found", smsShell)
		return
	}

	cmd := exec.Command(smsShell, phone, "'"+sms+"'")
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
	err := cmd.Start()
	if err != nil {
		log.Printf("start cmd err: %v shell:%v", err, smsShell)
	}
	err, isTimeout := sys.CmdRunWithTimeout(cmd, time.Second*10)
	log.Printf("%s %s %s", smsShell, phone, sms)
	if err != nil {
		log.Printf("err: %v, isTimeout: %v", err, isTimeout)
	}

	return
}

func sendMail(mail *g.Mail) {
	defer func() {
		<-MailWorkerChan
	}()

	//s := smtp.New(g.Config.Smtp.Addr, g.Config.Smtp.Username, g.Config.Smtp.Password)
	s := smtp.NewSMTP(g.Config.Smtp.Addr, g.Config.Smtp.Username, g.Config.Smtp.Password, g.Config.Smtp.Tls, false, false)
	err := s.SendMail(g.Config.Smtp.From, strings.Replace(mail.Tos, ",", ";", -1), mail.Subject, mail.Content, "text")
	if err != nil {
		log.Printf("send mail err:%v tos:%v\n", err, mail.Tos)
		return
	}

	if g.Config.Debug {
		log.Println("==mail==>>>>", mail)
	}
}

func sendWeChat(weChat *g.WeChat) {
	defer func() {
		<-WeChatWorkerChan
	}()

	var msg = weChatMsg{
		ToUser:  weChat.Tos,
		ToParty: g.Config.WeChat.ToParty,
		MsgType: "text",
		AgentId: g.Config.WeChat.AgentId,
		Text:    map[string]string{"content": weChat.Content},
	}
	token, err := GetToken(g.Config.WeChat.CorpId, g.Config.WeChat.CorpSecret)
	buf, err := json.Marshal(msg)
	if err != nil {
		log.Println(err, "get weChat token error")
	}
	err = SendMsg(token.AccessToken, buf)
	if err != nil {
		log.Println(err, "send weChat")
	} else {
		log.Println("==weChat==>>>>", weChat)
		log.Println("<<<<==weChatMsg==", string(buf))
	}
}

func getUsers(sid int64) []*dataobj.User {
	var usersResp api.UsersResponse
	var users []*dataobj.User
	strategy, exists := cache.StrategyMap.Get(sid)
	if !exists {
		log.Printf("strategyId: %d not exists", sid)
		return users
	}

	err := backend.CallRpc("Web.GetUsersByTeam", strategy.Teams, &usersResp)
	if err != nil {
		log.Println("Web.GetUsersByTeam Error:", err)
		return users
	}

	if usersResp.Message != "" {
		log.Println("Web.GetUsersByTeam Error:", usersResp.Message)
		return users
	}
	users = usersResp.Data

	return users
}

// 定义微信文本消息结构体
type weChatMsg struct {
	ToUser  string            `json:"touser"`
	ToParty string            `json:"toparty"`
	MsgType string            `json:"msgtype"`
	AgentId int               `json:"agentid"`
	Text    map[string]string `json:"text"`
	Safe    int               `json:"safe"`
}

// 定义微信错误返回结构体
type sendMsgError struct {
	ErrCode int    `json:"errcode`
	ErrMsg  string `json:"errmsg"`
}

// 定义token结构体
type accessToken struct {
	AccessToken string `json:"access_token"`
	ExpiresIn   int    `json:"expires_in"`
}

// 获取返回
func GetToken(corpId, corpSecret string) (at accessToken, err error) {
	resp, err := http.Get(getToken + corpId + "&corpSecret=" + corpSecret)
	if err != nil {
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		err = requestError
		return
	}
	buf, _ := ioutil.ReadAll(resp.Body)
	err = json.Unmarshal(buf, &at)
	if at.AccessToken == "" {
		err = errors.New("微信企业号中的标识或者应用Secret错误")
	}
	return
}

// 发送微信
func SendMsg(AccessToken string, msgBody []byte) error {
	body := bytes.NewBuffer(msgBody)
	resp, err := http.Post(sendUrl+AccessToken, "application/json", body)
	if resp.StatusCode != 200 {
		return requestError
	}
	buf, _ := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	var e sendMsgError
	err = json.Unmarshal(buf, &e)
	if err != nil {
		return err
	}
	if e.ErrCode != 0 && e.ErrMsg != "ok" {
		return errors.New(string(buf))
	}
	return nil
}
