package main

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/axgle/mahonia"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

const (
	FS_App_ID      = `cli_a30a3f495979500e`
	FS_App_Secrets = `uOSt29KI7aCsPyn4H9YfEbCnP6Mptfu2`

	//Test_Group_Chat_ID     = `oc_307774ba969e82dde34cc77e071f8784` // 测试群的 chat_id
	Security_Group_Chat_ID = `oc_1ff1a009099b8b559cfc7d3ea28fcaa8` // Security Group ID

	//消息模板，替换 user_open_id 、send_message、notice_title(用户的openid 消息内容 消息标题)
	Template_Notice = `
{
    "receive_id": "user_open_id",
    "content": "{\"config\":{\"wide_screen_mode\":true},\"elements\":[{\"tag\":\"div\",\"text\":{\"content\":\"send_message\",\"tag\":\"lark_md\"}}],\"header\":{\"template\":\"turquoise\",\"title\":{\"content\":\"notice_title\",\"tag\":\"plain_text\"}}}",
    "msg_type": "interactive"
}
`

	ShieldAdvanced_Ratelimit_Alarm_Title  = `ShieldAdvanced Alarm(layer 2)`
	ShieldAdvanced_Ratelimit_Alarm_messag = `Monitoring shows DDOS attack`
)

func handler(ctx context.Context, snsEvent events.SNSEvent) error {
	var snsJSONstr, encode_base64 string
	// 遍历所有 SNS 消息
	for _, record := range snsEvent.Records {
		sns := record.SNS

		// 打印完整 JSON 消息
		snsJSON, err := json.MarshalIndent(sns, "", "  ")
		if err != nil {
			return fmt.Errorf("failed to marshal SNS message: %v", err)
		}
		snsJSONstr = string(snsJSON)
		encode_base64 = base64.URLEncoding.EncodeToString([]byte(snsJSONstr))
		fmt.Println("SNS Message JSON:")
		fmt.Println("")
		fmt.Println("-----------------------------------------")
		fmt.Println(snsJSONstr)
		fmt.Println("-----------------------------------------")
	}

	// get TopicArn
	TopicArn, err := RegxStr(snsJSONstr, `"TopicArn":[^,]+`)
	if err != nil {
		return err
	}
	TopicArn = strings.ReplaceAll(TopicArn, `"TopicArn":`, "")
	TopicArn = strings.ReplaceAll(TopicArn, `"`, "")
	TopicArn = strings.TrimSpace(TopicArn)

	// get Alarm name
	AlarmName, err := RegxStr(snsJSONstr, `\\"AlarmName\\":[^,]+`)
	if err != nil {
		return err
	}
	AlarmName = strings.ReplaceAll(AlarmName, `\"AlarmName\":`, "")
	AlarmName = strings.ReplaceAll(AlarmName, `\"`, "")
	AlarmName = strings.TrimSpace(AlarmName)

	Send_Group_Notice(Security_Group_Chat_ID, ShieldAdvanced_Ratelimit_Alarm_Title, ShieldAdvanced_Ratelimit_Alarm_messag+"\n"+TopicArn+"\n"+AlarmName+"\n"+"\n"+encode_base64)
	return nil
}

func Get_Tenant_AccessToken() (string, error) {
	var postdata string
	postdata = `{"app_id": "` + FS_App_ID + `","app_secret": "` + FS_App_Secrets + `"}`
	//fmt.Println(postdata)
	respdata, err := HTTP_Req_POST("https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal", postdata)
	if err != nil {
		return "", err
	}
	resp1, err1 := RegxStr(respdata, `"app_access_token":"t-[0-9a-zA-Z]+"`)
	if err1 != nil {
		return "", err
	}
	resp2, err2 := RegxStr(resp1, `t-[0-9a-zA-Z]+`)
	if err2 != nil {
		return "", err
	}
	return resp2, err
}

/*
发送飞书群消息函数
receive_id 为飞书群 ID，在发送消息的选择群组中可获取
*/
func Send_Group_Notice(receive_id string, title string, sendmessage string) error {
	receive_id = strings.TrimSpace(receive_id)
	title = strings.TrimSpace(title)
	sendmessage = strings.TrimSpace(sendmessage)
	//获取 header token
	APP_Token, aterr := Get_Tenant_AccessToken()
	if aterr != nil {
		return aterr
	}

	//send message to user
	APP_Token, aterr = Get_Tenant_AccessToken()
	if aterr != nil {
		return aterr
	}
	send_msg_url := "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id"
	send_message_data := strings.ReplaceAll(Template_Notice, "user_open_id", receive_id) //user open id
	sendmessage = strings.ReplaceAll(sendmessage, "\n", `\\n`)
	send_message_data = strings.ReplaceAll(send_message_data, "send_message", sendmessage)
	send_message_data = strings.ReplaceAll(send_message_data, "notice_title", title)

	_, serr := HTTP_POST(send_msg_url, APP_Token, send_message_data)
	if serr != nil {
		return serr
	}

	return nil
}

func HTTP_POST(Hurl string, ha string, postdata string) (string, error) {
	req, err := http.NewRequest("POST", Hurl, strings.NewReader(postdata))
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0")
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2")
	//req.Header.Set("Accept-Encoding","gzip, deflate")
	req.Header.Set("Upgrade-Insecure-Requests", "1")
	req.Header.Set("Sec-Fetch-Dest", "document")
	req.Header.Set("Sec-Fetch-Mode", "navigate")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+ha)
	//req.Header.Set("Content-Type","application/x-www-form-urlencoded")
	//req.Header.Set("Cookie","lianan")
	client := &http.Client{
		Timeout: time.Millisecond * 10000,
	}
	resp2, err := client.Do(req)
	if err != nil {
		return "", err
	}
	body, err := ioutil.ReadAll(resp2.Body)
	if err != nil {
		return "", err
	}
	resp2.Body.Close()
	Retexecstr := mahonia.NewDecoder("gbk").ConvertString(string(body))
	return Retexecstr, nil
}

/*
Hurl --> http url
postdata   --> The data that needs to be submitted by post
string --> Return the requested data
*/
func HTTP_Req_POST(Hurl string, postdata string) (string, error) {
	req, err := http.NewRequest("POST", Hurl, strings.NewReader(postdata))
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0")
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2")
	//req.Header.Set("Accept-Encoding","gzip, deflate")
	req.Header.Set("Upgrade-Insecure-Requests", "1")
	req.Header.Set("Sec-Fetch-Dest", "document")
	req.Header.Set("Sec-Fetch-Mode", "navigate")
	req.Header.Set("Content-Type", "application/json")
	//req.Header.Set("Content-Type","application/x-www-form-urlencoded")
	//req.Header.Set("Cookie","lianan")
	client := &http.Client{
		Timeout: time.Millisecond * 10000,
	}
	resp2, err := client.Do(req)
	if err != nil {
		return "", err
	}
	body, err := ioutil.ReadAll(resp2.Body)
	if err != nil {
		return "", err
	}
	resp2.Body.Close()
	Retexecstr := mahonia.NewDecoder("gbk").ConvertString(string(body))
	return Retexecstr, nil
}

func RegxStr(datastr string, regx string) (string, error) {
	//Regular test, the MatchString function can only judge whether it can be matched, and return true if it can match, otherwise return false
	_, errs := regexp.MatchString(regx, datastr)
	if errs != nil {
		return "", errs
	}

	//Traverse the matching content
	comstr := regexp.MustCompile(regx)
	matchstr := comstr.FindAllString(datastr, -1)
	var regxres string = ""
	for x := range matchstr { //通过range函数遍历，打印全部输出
		regxres = regxres + matchstr[x] + "\n"
	}
	regxres = strings.TrimRight(regxres, "\n")
	return regxres, nil
}

func main() {
	lambda.Start(handler)
}
