package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"sort"
	"strings"
)

const (
	REQ_ACCESS_POP_TIMESTRAP = "access-pop-timestrap"
	REQ_ACCESS_POP_NONCESTR  = "access-pop-noncestr"
	REQ_ACCESS_POP_SIGNATURE = "access-pop-signature"
	REQ_ACCESS_POP_TOKEN     = "access-pop-token"
	HMAC_SHA256_ALGORITHM    = "HmacSHA256"
)

func main() {
	// 示例数据
	data := map[string]string{
		REQ_ACCESS_POP_TOKEN:     "4fb818df-af9e-4590-868f-52a6647cb91b9a6a7474-5891-4468-84fb-ccd0beef91a5",
		REQ_ACCESS_POP_TIMESTRAP: "cdd08ede-b836-44d2-8c10-b6abc0ac57aa",
		REQ_ACCESS_POP_NONCESTR:  "abcabcabcabcabc1",
	}

	// 获取当前时间戳
	//timestrap := time.Now().UnixNano() / int64(time.Millisecond)

	// 对数据进行排序
	keys := make([]string, 0, len(data))
	for k := range data {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	var sortedData []string
	for _, k := range keys {
		sortedData = append(sortedData, fmt.Sprintf("%s=%s", k, data[k]))
	}

	// 拼接数据
	//signStr := fmt.Sprintf("%d\n%s\n%s\n%s", timestrap, strings.Join(sortedData, "\n"), REQ_ACCESS_POP_TOKEN, "cdd08ede-b836-44d2-8c10-b6abc0ac57aa")	signStr := fmt.Sprintf("%d\n%s\n%s\n%s", timestrap, strings.Join(sortedData, "\n"), REQ_ACCESS_POP_TOKEN, "cdd08ede-b836-44d2-8c10-b6abc0ac57aa")
	signStr := fmt.Sprintf("%d\n%s\n%s\n%s", REQ_ACCESS_POP_TIMESTRAP, strings.Join(sortedData, "\n"), REQ_ACCESS_POP_TOKEN, "cdd08ede-b836-44d2-8c10-b6abc0ac57aa")
	// 计算 HMAC-SHA256
	key := []byte("cdd08ede-b836-44d2-8c10-b6abc0ac57aa")
	h := hmac.New(sha256.New, key)
	h.Write([]byte(signStr))
	signature := hex.EncodeToString(h.Sum(nil))

	// 打印签名结果
	fmt.Println(signature)
}

func chkSignature(accessToken string, timestrap string, nonceStr string, signature string, signatureKey string) bool {
	treeMap := map[string]string{
		REQ_ACCESS_POP_TOKEN:     accessToken,
		REQ_ACCESS_POP_TIMESTRAP: timestrap,
		REQ_ACCESS_POP_NONCESTR:  nonceStr,
	}

	// 对数据进行排序
	keys := make([]string, 0, len(treeMap))
	for k := range treeMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	var sortedData []string
	for _, k := range keys {
		sortedData = append(sortedData, fmt.Sprintf("%s=%s", k, treeMap[k]))
	}

	// 拼接数据
	signStr := fmt.Sprintf("%s\n%s\n%s\n%s", accessToken, timestrap, nonceStr, signatureKey)

	// 计算 HMAC-SHA256
	key := []byte(signatureKey)
	h := hmac.New(sha256.New, key)
	h.Write([]byte(signStr))
	sysSignature := hex.EncodeToString(h.Sum(nil))

	if sysSignature != signature {
		log.Printf("签名不一致！%s -> %s", sysSignature, signature)
		return false
	}

	return true
}

func getObjectMd5Value(obj interface{}) string {
	bytes, err := json.Marshal(obj)
	if err != nil {
		log.Printf("json.Marshal error: %v", err)
		return ""
	}

	h := sha256.New()
	h.Write(bytes)

	return hex.EncodeToString(h.Sum(nil))
}

func postJson(url string, data interface{}, headers http.Header) ([]byte, error) {
	bytesData, err := json.Marshal(data)
	if err != nil {
		return nil, fmt.Errorf("json.Marshal error: %v", err)
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(bytesData))
	if err != nil {
		return nil, fmt.Errorf("http.NewRequest error: %v", err)
	}

	req.Header.Set("Content-Type", "application/json")
	for k, v := range headers {
		req.Header[k] = v
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("client.Do error: %v", err)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("ioutil.ReadAll error: %v", err)
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("response status code not OK: %d, response body: %s", resp.StatusCode, string(body))
	}

	return body, nil
}
