package fileOss

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"encoding/json"
	"epur-pay/pkg/idGenerate"
	"epur-pay/pkg/utils"
	"fmt"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"hash"
	"io"
	"reflect"
	"time"
)

type ConfigStruct struct {
	Expiration string     `json:"expiration"`
	Conditions [][]string `json:"conditions"`
}

type CallbackParam struct {
	CallbackUrl      string `json:"callbackUrl"`
	CallbackBody     string `json:"callbackBody"`
	CallbackBodyType string `json:"callbackBodyType"`
}

/*
阿里云oss存储
*/
type Oss struct {
	Key             string
	AccessKeyId     string
	AccessKeySecret string
	BucketName      string
	EndPoint        string
	Access          string
	RegionId        string
	ReadPrivate     bool
	client          *oss.Client
	bucket          *oss.Bucket
}

func New(accessKeyId, accessKeySecret, bucketName, endPoint string, access string, RegionId string, private bool) (*Oss, error) {

	var instance *Oss
	instance = &Oss{
		ReadPrivate:     private,
		AccessKeyId:     accessKeyId,
		AccessKeySecret: accessKeySecret,
		BucketName:      bucketName,
		EndPoint:        endPoint,
		RegionId:        RegionId,
		Access:          access,
	}
	if err := instance.init(instance.AccessKeyId, instance.AccessKeySecret, instance.BucketName, instance.EndPoint); err != nil {
		return nil, err
	}
	return instance, nil
}

func (this *Oss) ReadUrl(filePath string) string {
	return this.url(filePath)
}

func (this *Oss) init(accessKeyId, accessKeySecret, bucketName, endPoint string) error {
	var err error
	this.client, err = oss.New(endPoint, accessKeyId, accessKeySecret)
	if err != nil {
		return err
	}
	if bucketName != "" {
		this.bucket, err = this.client.Bucket(bucketName)
		if err != nil {
			return err
		}
	}
	return nil
}

func (this *Oss) url(fileName string) string {
	return fmt.Sprintf("https://%s/%s", this.Access, fileName)
}

func (this *Oss) Put(fileName string, contentType string, data interface{}) string {

	var ossData io.Reader

	typeOf := reflect.TypeOf(data).Kind()

	//logger.AccessLogger.Infoln("fileName: ", fileName, " 类型:", typeOf)
	//logger.AccessLogger.Infoln("contentType: ", contentType)

	switch typeOf {
	case reflect.Slice:
		ossData = bytes.NewBuffer(data.([]byte))
	case reflect.Struct:
		ossData = data.(io.Reader)
	case reflect.Ptr:
		a1 := reflect.ValueOf(data).Interface()
		d := a1.([]uint8)
		ossData = bytes.NewBuffer(d)
	default:
		panic("数据不合法--!")
	}

	oss.SetHeader("content-type", contentType)
	utils.Error(this.bucket.PutObject(fileName, ossData))
	return this.url(fileName)
}

func (this *Oss) Get_gmt_iso8601(expire_end int64) string {
	var tokenExpire = time.Unix(expire_end, 0).UTC().Format("2006-01-02T15:04:05Z")
	return tokenExpire
}

// 获取直传token
func (this *Oss) Token(key string, contentType string) (map[string]interface{}, error) {
	now := time.Now().Unix()
	expire_end := now + 300
	tokenExpire := this.Get_gmt_iso8601(expire_end)
	//create post policy json
	var config ConfigStruct
	config.Expiration = tokenExpire
	var condition []string
	condition = append(condition, "starts-with")
	condition = append(condition, "$key")
	condition = append(condition, "pic")
	config.Conditions = append(config.Conditions, condition)

	//calucate signature
	result, err := json.Marshal(config)
	debyte := base64.StdEncoding.EncodeToString(result)
	h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(this.AccessKeySecret))
	io.WriteString(h, debyte)
	signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))

	var callbackParam CallbackParam
	callbackParam.CallbackUrl = ""
	callbackParam.CallbackBody = "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}"
	callbackParam.CallbackBodyType = "application/x-www-form-urlencoded"
	callback_str, err := json.Marshal(callbackParam)
	if err != nil {
		fmt.Println("callback json err:", err)
	}
	callbackBase64 := base64.StdEncoding.EncodeToString(callback_str)

	token := make(map[string]interface{})

	token["accessId"] = this.AccessKeyId
	token["host"] = fmt.Sprintf("https://%s", this.Access)
	token["expire"] = expire_end
	token["signature"] = signedStr
	token["directory"] = "pic"
	token["policy"] = debyte
	token["callback"] = callbackBase64
	token["x:callbackkey"] = utils.EncodeMD5(idGenerate.ID.Generate(""))

	return token, nil
}