package fileAsw

import (
	"bytes"
	"epur-pay/pkg/logger"
	"epur-pay/pkg/utils"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	"io"
	"reflect"
	"time"
)

/*
亚马逊oss存储
*/
type S3 struct {
	Path            string
	AccessKeyId     string
	AccessKeySecret string
	BucketName      string
	EndPoint        string
	RegionId        string
	Access          string
	ReadPrivate     bool
	sess            *session.Session
	svc             *s3.S3
}

func New(accessKeyId, accessKeySecret, bucket, endPoint, access, regionId string) (*S3, error) {
	var instance *S3
	instance = &S3{
		Path:            "exchange",
		BucketName:      bucket,
		AccessKeyId:     accessKeyId,
		AccessKeySecret: accessKeySecret,
		EndPoint:        endPoint,
		RegionId:        regionId,
		Access:          access,
	}

	sess, err := session.NewSession(&aws.Config{
		Credentials:      credentials.NewStaticCredentials(instance.AccessKeyId, instance.AccessKeySecret, ""),
		Endpoint:         aws.String(instance.EndPoint),
		Region:           aws.String(instance.RegionId),
		DisableSSL:       aws.Bool(false), // true - 本地http false -- 远端
		S3ForcePathStyle: aws.Bool(false),
	})

	if err != nil {
		return nil, err
	}

	instance.sess = sess
	instance.svc = s3.New(sess)

	return instance, nil
}

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

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

func (this *S3) Put(fileName string, contentType string, data interface{}) string {
	var ossData io.Reader
	var err error
	typeOf := reflect.TypeOf(data).Kind()
	logger.AccessLogger.Infoln("ContentType ", contentType, "typeOf ", typeOf)

	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()

		switch v := a1.(type) {
		case []uint8:
			// 处理 []uint8 类型的情况
			logger.AccessLogger.Infoln("It's a []uint8 slice:", v)
		case string:
			// 处理 string 类型的情况
			logger.AccessLogger.Infoln("It's a string:", &v)
		default:
			// 处理其他类型的情况
			logger.AccessLogger.Infoln("It's some other type:", &v)
		}

		d, ok := a1.([]uint8)
		if !ok {
			logger.AccessLogger.Errorf("---> Upload Ptr Error. %+v", a1)
		}
		ossData = bytes.NewBuffer(d)
	default:
		panic("数据不合法--!")
	}

	//if len(contentType) <= 0 {
	contentType, err = utils.GetContentTypeForIoRead(fileName, ossData)
	if err != nil {
		logger.ErrorLogger.Errorln(err.Error())
	}
	//}

	uploader := s3manager.NewUploader(this.sess)
	_, err = uploader.Upload(&s3manager.UploadInput{
		Bucket:      aws.String(fmt.Sprintf("%s/", this.BucketName)),
		Key:         aws.String(fmt.Sprintf("%s/%s", this.Path, fileName)),
		Body:        ossData,
		ContentType: aws.String(contentType),
		//ACL:         aws.String("public-read"),
	})

	if err != nil {
		return err.Error()
	}

	return this.url(fileName)
}

// 获取预签名地址
func (this *S3) Token(key string, contentType string) (map[string]interface{}, error) {
	params := &s3.PutObjectInput{
		Bucket:      aws.String(fmt.Sprintf("%s/", this.BucketName)),
		Key:         aws.String(fmt.Sprintf("%s/%s", this.Path, key)),
		ContentType: &contentType,
	}

	req, _ := this.svc.PutObjectRequest(params)
	url, err := req.Presign(15 * time.Minute)
	if err != nil {
		logger.AccessLogger.Errorln("---> %s ", err.Error())
		return nil, err
	}

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

	token["token"] = url
	token["url"] = this.ReadUrl(key)
	return token, err
}