package services

import (
	"bytes"
	"crypto/tls"
	"eta/eta_api/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"
	"io/ioutil"
	"net/http"
	"time"
)

type OssClient interface {
	UploadFile(string, string, string) (string, error)
	GetUploadToken() (OssToken, error)
}

func NewOssClient() OssClient {
	switch utils.ObjectStorageClient {
	case utils.STORAGESOURCE_MINIO_NAME:
		return new(MinioOss)
	case utils.STORAGESOURCE_S3_NAME:
		return new(S3Oss)
	default:
		// 默认使用阿里云OSS
		return new(AliOss)
	}
}

// OssToken 此处为了兼容前端那边所以有重复的
type OssToken struct {
	AccessKeyId string
	SecretKeyId string
	RegionId    string
	Bucketname  string
	Endpoint    string
	ImgHost     string
	UseSSL      string
	Port        string
	//AccessKeyId     string
	AccessKeySecret string
	SecurityToken   string
	ExpiredTime     string
	//RegionId        string
	//Bucketname      string
	//Endpoint        string
	Imghost      string
	S3ForceStyle bool
	S3Protocol   string
}

type S3Oss struct{}

func (m *S3Oss) UploadFile(fileName, localFile, savePath string) (resourceUrl string, err error) {
	defer func() {
		if err != nil {
			fmt.Println(err.Error())
		}
	}()

	// 默认使用后端这个, 这里有两个配置的原因是
	// 前端上传跨域问题可能会使用反向代理来解决, 这样的话同一个endpoint就会导致一端正常另一端不正常
	endpoint := utils.S3BackEndpoint
	if endpoint == "" {
		endpoint = utils.S3Endpoint
	}
	accessKey := utils.S3AccessKeyId
	secretKey := utils.S3AccessKeySecret
	region := utils.S3Region
	bucketName := utils.S3BucketName
	uploadDir := utils.S3UploadDir
	resourceHost := utils.S3Host
	forceStyle := utils.S3ForceStyle
	hostStyle := true // 默认true, 使用`endpoint/bucket_name`这种HOST格式
	if forceStyle == "false" {
		hostStyle = false
	}
	disableSSL := true // 默认true, 跳过SSL
	if utils.S3DisableSSL == "false" {
		disableSSL = false
	}
	//fmt.Println("disableSSL: ", disableSSL)

	config := &aws.Config{
		Region:           aws.String(region),
		Credentials:      credentials.NewStaticCredentials(accessKey, secretKey, ""),
		Endpoint:         aws.String(endpoint),
		S3ForcePathStyle: aws.Bool(hostStyle),
		DisableSSL:       aws.Bool(disableSSL),
	}
	if disableSSL {
		config.HTTPClient = &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			},
		}
	}
	//b, _ := json.Marshal(config)
	//fmt.Println(string(b))

	// 创建AWS会话
	sess, e := session.NewSession(config)
	if e != nil {
		err = fmt.Errorf("new session err: %s", e.Error())
		return
	}

	// 创建S3服务客户端
	client := s3.New(sess)

	// 读取文件内容
	fileContent, e := ioutil.ReadFile(localFile)
	if e != nil {
		err = fmt.Errorf("read file err: %s", e.Error())
		return
	}

	path := savePath
	if savePath == "" {
		path = uploadDir + time.Now().Format("200601/20060102/") + fileName
	}
	putObjectInput := &s3.PutObjectInput{
		Bucket: aws.String(bucketName),
		Key:    aws.String(path),
		Body:   bytes.NewReader(fileContent),
	}
	if utils.S3OpenAcl == "1" {
		putObjectInput.ACL = aws.String(s3.ObjectCannedACLPublicRead)
	}
	fmt.Printf("put object input: %+v\n", putObjectInput)
	_, e = client.PutObject(putObjectInput)
	if e != nil {
		err = fmt.Errorf("put object err: %s", e.Error())
		return
	}
	resourceUrl = resourceHost + path
	if utils.ResourceProxyUrl != "" {
		resourceUrl = utils.ResourceProxyUrl + path
	}
	return
}

func (m *S3Oss) GetUploadToken() (token OssToken, err error) {
	token.Endpoint = utils.S3Endpoint
	token.AccessKeyId = utils.S3AccessKeyId
	token.AccessKeySecret = utils.S3AccessKeySecret
	token.RegionId = utils.S3Region
	token.Bucketname = utils.S3BucketName
	token.ImgHost = utils.S3Host
	token.Port = utils.S3EndpointPort
	hostStyle := true // 默认true, 使用`endpoint/bucket_name`这种HOST格式
	if utils.S3ForceStyle == "false" {
		hostStyle = false
	}
	token.S3ForceStyle = hostStyle
	token.S3Protocol = utils.S3Protocol
	return
}
