package upyun

import (
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"pychr/global"
	"strings"
	"time"
)

const (
	effectiveDuration = time.Minute * 30
)

type FormAPIToken struct {
	Bucket        string
	Method        string
	Authorization string
	XUpYunExpire  int64
	Policy        string
	Date          string
}

type Policy struct {
	Bucket     string `json:"bucket"`
	SaveKey    string `json:"save-key"`
	Expiration int64  `json:"expiration"`
	// ContentMD5 string `json:"content-md5"`
}

func makeSaveKey() string {
	return "/{year}/{mon}/{day}/upload_{random32}{.suffix}"
}

func makePolicy(bucket, saveKey string) (string, int64) {
	expiration := time.Now().Add(effectiveDuration).Unix()
	obj := Policy{
		Bucket:     bucket,
		SaveKey:    saveKey,
		Expiration: expiration,
		// ContentMD5:       content-md5,
	}

	str, err := json.Marshal(&obj)
	if err != nil {
		return "", 0
	}

	sEnc := base64.StdEncoding.EncodeToString([]byte(str))
	return sEnc, expiration
}

func md5Str(s string) string {
	return fmt.Sprintf("%x", md5.Sum([]byte(s)))
}
func makeRFC1123Date(d time.Time) string {
	utc := d.UTC().Format(time.RFC1123)
	return strings.Replace(utc, "UTC", "GMT", -1)
}
func base64ToStr(b []byte) string {
	return base64.StdEncoding.EncodeToString(b)
}
func sign(key, secret, method, uri, date, policy, md5 string) string {
	mac := hmac.New(sha1.New, []byte(secret))
	elems := []string{}
	for _, v := range []string{method, uri, date, policy, md5} {
		if v != "" {
			elems = append(elems, v)
		}
	}
	value := strings.Join(elems, "&")
	mac.Write([]byte(value))
	signStr := base64ToStr(mac.Sum(nil))
	return "UPYUN " + key + ":" + signStr
}

func GetUpyunToken(method, saveKey string) (r FormAPIToken, err error) {
	method = strings.ToUpper(method)
	date := makeRFC1123Date(time.Now())
	policy, expiration := makePolicy(global.GVA_CONFIG.CDN.Bucket, saveKey)
	authorization := sign(global.GVA_CONFIG.CDN.Bucket, md5Str(global.GVA_CONFIG.CDN.Password), method, "/"+global.GVA_CONFIG.CDN.Bucket, "", policy, "")

	r.Bucket = global.GVA_CONFIG.CDN.Bucket
	r.Method = method
	r.XUpYunExpire = expiration
	r.Authorization = authorization
	r.Policy = policy
	r.Date = date

	return
}
