package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/aws/aws-lambda-go/lambda"
	"github.com/google/uuid"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sqs"
)

type BaiduSecretResp struct {
	Status int `json:"status"`
	Data string `json:"data"`
}

type IndexData struct {
	Date string `json:"date,omitempty"`
	Name string `json:"name,omitempty"`
	All string `json:"all,omitempty"`
	Pc string `json:"pc,omitempty"`
	Wise string `json:"wise,omitempty"`
}

type BaiduIndexResp struct {
	Status int `json:"status"`
	Data struct {
		UserIndexes []struct {
			Word []struct {
				Name string `json:"name"`
				WordType int `json:"wordType"`
			} `json:"word"`
			All struct {
				StartDate string `json:"startDate"`
				EndDate string `json:"endDate"`
				Data string `json:"data"`
			} `json:"all"`
			Pc struct {
				StartDate string `json:"startDate"`
				EndDate string `json:"endDate"`
				Data string `json:"data"`
			} `json:"pc"`
			Wise struct {
				StartDate string `json:"startDate"`
				EndDate string `json:"endDate"`
				Data string `json:"data"`
			} `json:"wise"`
			Type string `json:"type"`
		} `json:"userIndexes"`
		//GeneralRatio []struct {
		//	Word []struct {
		//		Name string `json:"name"`
		//		WordType int `json:"wordType"`
		//	} `json:"word"`
		//	All struct {
		//		Avg int `json:"avg"`
		//		Yoy int `json:"yoy"`
		//		Qoq int `json:"qoq"`
		//	} `json:"all"`
		//	Pc struct {
		//		Avg int `json:"avg"`
		//		Yoy int `json:"yoy"`
		//		Qoq int `json:"qoq"`
		//	} `json:"pc"`
		//	Wise struct {
		//		Avg int `json:"avg"`
		//		Yoy int `json:"yoy"`
		//		Qoq int `json:"qoq"`
		//	} `json:"wise"`
		//} `json:"generalRatio"`
		Uniqid string `json:"uniqid"`
	} `json:"data"`
	Logid int64 `json:"logid"`
	Message int `json:"message"`
}

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

func getRequest(url string, params map[string]string, bodyData interface{}) (*http.Request, error) {
	var body io.Reader
	body = nil
	if body != nil {
		bodyBytes, err := json.Marshal(bodyData)
		if err != nil {
			return nil, err
		}
		body = bytes.NewReader(bodyBytes)
	}

	req, err := http.NewRequest(http.MethodGet, url, body)
	if err != nil {
		return nil, err
	}

	q := req.URL.Query()
	for k, v := range params {
		q.Add(k, v)
	}
	fmt.Println(req.URL.String())
	req.URL.RawQuery = q.Encode()
	return req, err
}

func do(req *http.Request) (*http.Response, error) {
	cli := http.DefaultClient
	return cli.Do(req)
}

func baiduIndex() {
	rand.Seed(time.Now().UnixNano())
	cookie := os.Getenv("cookie")
	day := os.Getenv("day")

	indexs := []string{
		"[[{\"name\":\"tidb\",\"wordType\":1}],[{\"name\":\"oceanbase\",\"wordType\":1}],[{\"name\":\"goldendb\",\"wordType\":1}],[{\"name\":\"达梦\",\"wordType\":1}],[{\"name\":\"pingcap\",\"wordType\":1}]]",
	}

	indexData := []IndexData{}
	for _, index := range indexs {
		retry:
		params := map[string]string {
			"area": "0",
			"days":day,
		}
		params["word"] = index
		req, err := getRequest("https://index.baidu.com/api/SearchApi/index", params, nil)
		if err != nil {
			log.Fatal(err)
		}

		req.Header.Add("Cookie", cookie)
		resp, err := do(req)
		if err != nil {
			log.Fatal(err)
		}
		defer resp.Body.Close()
		bodyBytes, err := io.ReadAll(resp.Body)
		if err != nil {
			log.Fatal(err)
		}

		bdIndexData := BaiduIndexResp{}
		err = json.Unmarshal(bodyBytes, &bdIndexData)
		if err != nil {
			log.Println("json unmarshal failed, ", string(bodyBytes), err)
			time.Sleep(time.Duration(rand.Intn(10)+5)*time.Second)
			goto retry
		}

		params = map[string]string {
			"uniqid":bdIndexData.Data.Uniqid,
		}
		req, err = getRequest("https://index.baidu.com/Interface/ptbk", params, nil)
		if err != nil {
			log.Fatal(err)
		}

		req.Header.Add("Cookie", cookie)
		resp1, err := do(req)
		if err != nil {
			log.Fatal(err)
		}
		defer resp1.Body.Close()
		bodyBytes, err = io.ReadAll(resp1.Body)
		if err != nil {
			log.Fatal(err)
		}
		bdSecret := BaiduSecretResp{}
		err = json.Unmarshal(bodyBytes, &bdSecret)
		if err != nil {
			log.Fatal(err, string(bodyBytes))
		}

		tmp := washBaiduIndex(&bdIndexData, &bdSecret)
		indexData = append(indexData, tmp...)
		time.Sleep(time.Duration(rand.Intn(20)+5)*time.Second)
	}

	// send to sqs
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState: session.SharedConfigEnable,
	}))

	svc := sqs.New(sess)

	queue := "ingress-mim.fifo"
	result, err := svc.GetQueueUrl(&sqs.GetQueueUrlInput{
		QueueName: &queue,
	})

	if err != nil {
		log.Fatal(err)
	}

	for _, data := range indexData {
		dataJsonBytes, _ := json.Marshal(data)
		tmpBody := string(dataJsonBytes)
		_, err = svc.SendMessage(&sqs.SendMessageInput{
			MessageGroupId: aws.String("baidu-index"),
			MessageDeduplicationId: aws.String(uuid.NewString()),
			MessageBody: aws.String(tmpBody),
			QueueUrl:    result.QueueUrl,
		})

		if err != nil {
			log.Println(err)
		}
	}
	log.Println("Baiduindex done", indexData)
}


func decodeData(secret, data string) string {
	n := strings.Split(secret, "")
	m := map[string]string{}
	for i := 0; i < len(n) /2; i++ {
		m[n[i]] = n[len(n)/2+i]
	}

	e := strings.Split(data, "")
	decodeData := []string{}
	for i := 0; i < len(e); i++{
		decodeData = append(decodeData, m[e[i]])
	}

	return strings.Join(decodeData, "")
}

func washBaiduIndex(baiduIndex *BaiduIndexResp, secret *BaiduSecretResp) []IndexData {
	data := []IndexData{}
	for _, index := range baiduIndex.Data.UserIndexes {
		name := index.Word[0].Name
		begin := index.All.StartDate
		beginss := strings.Split(begin, "-")
		y, _ := strconv.Atoi(beginss[0])
		m, _ := strconv.Atoi(beginss[1])
		d, _ := strconv.Atoi(beginss[2])
		beginDate := time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Local)
		all := strings.Split(decodeData(secret.Data, index.All.Data), ",")
		pc := strings.Split(decodeData(secret.Data, index.Pc.Data), ",")
		wise := strings.Split(decodeData(secret.Data, index.Wise.Data), ",")

		for i:= 0; i < len(all); i++ {
			tmp := IndexData{}
			tmp.Name = name
			tmp.All = all[i]
			tmp.Pc = pc[i]
			if i < len(wise)  {
				tmp.Wise = wise[i]
			}
			tmp.Date = beginDate.AddDate(0,0,i).Format("2006-01-02")
			data = append(data, tmp)
		}
	}

	return data
}

