package main

import (
	"bytes"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"io"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/service/s3"
)

// === 桶操作 ===

func CreateBucket() {
	input := &s3.CreateBucketInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.CreateBucketRequest(input)
	send(req)
}

func ListBuckets() {
	req, _ := s3c.ListBucketsRequest(&s3.ListBucketsInput{})
	send(req)
}

func HeadBucket() {
	input := &s3.HeadBucketInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.HeadBucketRequest(input)
	send(req)
}

func DeleteBucket() {
	input := &s3.DeleteBucketInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.DeleteBucketRequest(input)
	send(req)
}

func GetBucketAcl() {
	input := &s3.GetBucketAclInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.GetBucketAclRequest(input)
	send(req)
}

func PutBucketAcl() {
	input := &s3.PutBucketAclInput{
		Bucket: aws.String(bucket),
		ACL:    aws.String("private"),
	}
	req, _ := s3c.PutBucketAclRequest(input)
	send(req)
}

func GetBucketPolicy() {
	input := &s3.GetBucketPolicyInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.GetBucketPolicyRequest(input)
	send(req)
}

func PutBucketPolicy() {
	// 一个允许禁止所有用户读取指定桶内对象的桶策略
	policy := `
	{
		"Version": "2012-10-17",
        "Id": "policy id",
		"Statement": [
			{
				"Sid": "statement id",
				"Effect": "Deny",
				"Principal": "*",
				"Action": "s3:GetObject",
				"Resource": [
					"arn:aws:s3:::YOUR-BUCKET-NAME/*"
				]
			}
		]
	}`
	input := &s3.PutBucketPolicyInput{
		Bucket: aws.String(bucket),
		Policy: aws.String(policy),
	}
	req, _ := s3c.PutBucketPolicyRequest(input)
	send(req)
}

func DeleteBucketPolicy() {
	input := &s3.DeleteBucketPolicyInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.DeleteBucketPolicyRequest(input)
	send(req)
}

func GetBucketVersioning() {
	input := &s3.GetBucketVersioningInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.GetBucketVersioningRequest(input)
	send(req)
}

func PutBucketVersioning() {
	input := &s3.PutBucketVersioningInput{
		Bucket: aws.String(bucket),
		VersioningConfiguration: &s3.VersioningConfiguration{
			Status: aws.String("Enabled"),
		},
	}
	req, _ := s3c.PutBucketVersioningRequest(input)
	send(req)
}

func GetBucketLifecycleConfiguration() {
	input := &s3.GetBucketLifecycleConfigurationInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.GetBucketLifecycleConfigurationRequest(input)
	send(req)
}

func PutBucketLifecycleConfiguration() {
	// 设置匹配指定前缀的对象一天后过期
	rule := &s3.LifecycleRule{
		ID:     aws.String("expireAfterOneDay"),
		Status: aws.String("Enabled"),
		Filter: &s3.LifecycleRuleFilter{
			Prefix: aws.String("expireAfterOneDay/"),
		},
		Expiration: &s3.LifecycleExpiration{
			Days: aws.Int64(1),
		},
	}
	input := &s3.PutBucketLifecycleConfigurationInput{
		Bucket: aws.String(bucket),
		LifecycleConfiguration: &s3.BucketLifecycleConfiguration{
			Rules: []*s3.LifecycleRule{rule},
		},
	}
	req, _ := s3c.PutBucketLifecycleConfigurationRequest(input)
	send(req)
}

func DeleteBucketLifecycle() {
	input := &s3.DeleteBucketLifecycleInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.DeleteBucketLifecycleRequest(input)
	send(req)
}

func GetBucketTagging() {
	input := &s3.GetBucketTaggingInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.GetBucketTaggingRequest(input)
	send(req)
}

func PutBucketTagging() {
	tagging := &s3.Tagging{
		TagSet: []*s3.Tag{
			{
				Key:   aws.String("key1"),
				Value: aws.String("value1"),
			},
		},
	}
	input := &s3.PutBucketTaggingInput{
		Bucket:  aws.String(bucket),
		Tagging: tagging,
	}
	req, _ := s3c.PutBucketTaggingRequest(input)
	send(req)
}

func DeleteBucketTagging() {
	input := &s3.DeleteBucketTaggingInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.DeleteBucketTaggingRequest(input)
	send(req)
}

func GetBucketEncryption() {
	input := &s3.GetBucketEncryptionInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.GetBucketEncryptionRequest(input)
	send(req)
}

func PutBucketEncryption() {
	serverSideEncryptionConfiguration := &s3.ServerSideEncryptionConfiguration{
		Rules: []*s3.ServerSideEncryptionRule{
			{
				ApplyServerSideEncryptionByDefault: &s3.ServerSideEncryptionByDefault{
					KMSMasterKeyID: aws.String(`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:::xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`),
					SSEAlgorithm:   aws.String(`aws:kms`),
				},
			},
		},
	}
	input := &s3.PutBucketEncryptionInput{
		Bucket:                            aws.String(bucket),
		ServerSideEncryptionConfiguration: serverSideEncryptionConfiguration,
	}
	req, _ := s3c.PutBucketEncryptionRequest(input)
	send(req)
}

func DeleteBucketEncryption() {
	input := &s3.DeleteBucketEncryptionInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.DeleteBucketEncryptionRequest(input)
	send(req)
}

// === 对象操作 ===

func GetObject() {
	input := &s3.GetObjectInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
	}
	req, _ := s3c.GetObjectRequest(input)
	send(req)
}

func PutObject() {
	// 以当前文件夹的指定文件作为输入
	file, err := os.Open("./go.mod")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	input := &s3.PutObjectInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
		Body:   file,
	}
	req, _ := s3c.PutObjectRequest(input)
	send(req)
}

func ListObjects() {
	input := &s3.ListObjectsInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.ListObjectsRequest(input)
	send(req)
}

func DeleteObject() {
	input := &s3.DeleteObjectInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
	}
	req, _ := s3c.DeleteObjectRequest(input)
	send(req)
}

func DeleteObjects() {
	input := &s3.DeleteObjectsInput{
		Bucket: aws.String(bucket),
		Delete: &s3.Delete{
			Objects: []*s3.ObjectIdentifier{
				{
					Key: aws.String("exampleKey1"),
				},
				{
					Key: aws.String("exampleKey2"),
				},
			},
		},
	}
	req, _ := s3c.DeleteObjectsRequest(input)
	send(req)
}

func CopyObject() {
	input := &s3.CopyObjectInput{
		Bucket:     aws.String(bucket),
		Key:        aws.String(key + `2`),
		CopySource: aws.String(bucket + `/` + key),
	}
	req, _ := s3c.CopyObjectRequest(input)
	send(req)
}

func HeadObject() {
	input := &s3.HeadObjectInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
	}
	req, _ := s3c.HeadObjectRequest(input)
	send(req)
}

func GetObjectTagging() {
	input := &s3.GetObjectTaggingInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
	}
	req, _ := s3c.GetObjectTaggingRequest(input)
	send(req)
}

func PutObjectTagging() {
	tagging := &s3.Tagging{
		TagSet: []*s3.Tag{
			{
				Key:   aws.String("key1"),
				Value: aws.String("value1"),
			},
		},
	}
	input := &s3.PutObjectTaggingInput{
		Bucket:  aws.String(bucket),
		Key:     aws.String(key),
		Tagging: tagging,
	}
	req, _ := s3c.PutObjectTaggingRequest(input)
	send(req)
}

func DeleteObjectTagging() {
	input := &s3.DeleteObjectTaggingInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
	}
	req, _ := s3c.DeleteObjectTaggingRequest(input)
	send(req)
}

func GetObjectAcl() {
	input := &s3.GetObjectAclInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
	}
	req, _ := s3c.GetObjectAclRequest(input)
	send(req)
}

func PutObjectAcl() {
	input := &s3.PutObjectAclInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
		ACL:    aws.String("private"),
	}
	req, _ := s3c.PutObjectAclRequest(input)
	send(req)
}

func ListObjectVersions() {
	input := &s3.ListObjectVersionsInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.ListObjectVersionsRequest(input)
	send(req)
}

func RestoreObject() {
	input := &s3.RestoreObjectInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
		RestoreRequest: &s3.RestoreRequest{
			Days: aws.Int64(1),
		},
	}
	req, _ := s3c.RestoreObjectRequest(input)
	send(req)
}

// === 分段上传操作 ===

func CreateMultipartUpload() {
	input := &s3.CreateMultipartUploadInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
	}
	req, _ := s3c.CreateMultipartUploadRequest(input)
	send(req)
}

func UploadPart() {
	data := bytes.NewReader([]byte("data"))
	input := &s3.UploadPartInput{
		Bucket:     aws.String(bucket),
		Key:        aws.String(key),
		UploadId:   aws.String("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"),
		Body:       data,
		PartNumber: aws.Int64(2),
	}
	req, _ := s3c.UploadPartRequest(input)
	send(req)
}

func ListParts() {
	input := &s3.ListPartsInput{
		Bucket:   aws.String(bucket),
		Key:      aws.String(key),
		UploadId: aws.String("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"),
	}
	req, _ := s3c.ListPartsRequest(input)
	send(req)
}

func AbortMultipartUpload() {
	input := &s3.AbortMultipartUploadInput{
		Bucket:   aws.String(bucket),
		Key:      aws.String(key),
		UploadId: aws.String("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"),
	}
	req, _ := s3c.AbortMultipartUploadRequest(input)
	send(req)
}

func CompletedMultipartUpload() {
	multipartUpload := &s3.CompletedMultipartUpload{
		Parts: []*s3.CompletedPart{
			{
				ETag:       aws.String("\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\""),
				PartNumber: aws.Int64(1),
			},
			{
				ETag:       aws.String("\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\""),
				PartNumber: aws.Int64(2),
			},
		},
	}
	input := &s3.CompleteMultipartUploadInput{
		Bucket:          aws.String(bucket),
		Key:             aws.String(key),
		UploadId:        aws.String("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"),
		MultipartUpload: multipartUpload,
	}
	req, _ := s3c.CompleteMultipartUploadRequest(input)
	send(req)
}

func ListMultipartUploads() {
	input := &s3.ListMultipartUploadsInput{
		Bucket: aws.String(bucket),
	}
	req, _ := s3c.ListMultipartUploadsRequest(input)
	send(req)
}

// === 图片操作 ===

func ProcessObject() {
	input := &s3.ProcessObjectInput{
		Bucket:        aws.String(bucket),
		Key:           aws.String(`after.jpg`),
		ProcessSource: aws.String(bucket + "/example.jpg"),
		ZosProcess:    aws.String(`image/crop,w_100,h_100,x_10,y_10,g_se`),
	}
	req, _ := s3c.ProcessObjectRequest(input)
	send(req)
}

func GetProcessedObject() {
	input := &s3.GetObjectInput{
		Bucket:     aws.String(bucket),
		Key:        aws.String("example.jpg"),
		ZosProcess: aws.String(`image/watermark,text_Q2hpbmF0ZWxlY29t,type_heiti,color_FF0000,size_40,g_center,t_80`),
	}
	output, err := s3c.GetObject(input)
	if err != nil {
		fmt.Printf("* Status: Fail\n* Output:\n%v\n* Error:\n%v\n", output, err)
	} else {
		// 将获取到对象写入当前文件夹的 output 文件
		reader := output.Body
		defer reader.Close()
		file, err := os.Create("output")
		if err != nil {
			panic(err)
		}
		defer file.Close()
		if _, err := io.Copy(file, reader); err != nil {
			panic(err)
		}
		fmt.Printf("* Status: Susccess\n* Output:\n%v\n", output)
	}
}

// === 其他操作 ===

func PresignGetObjectRequest() {
	input := &s3.GetObjectInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
	}
	// 构造请求
	request, _ := s3c.GetObjectRequest(input)
	// 设定预签名链接过期时间
	expire := 15 * time.Minute
	// 预签名请求
	output, err := request.Presign(expire)
	if err != nil {
		fmt.Printf("* Status: Fail\n* Output:\n%v\n* Error:\n%v\n", output, err)
	} else {
		fmt.Printf("* Status: Susccess\n* Output:\n%v\n", output)
	}
}

func PresignPutObjectRequest() {
	input := &s3.PutObjectInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
	}
	// 构造请求
	request, _ := s3c.PutObjectRequest(input)
	// 设定预签名链接过期时间
	expire := 15 * time.Minute
	// 预签名请求
	output, err := request.Presign(expire)
	if err != nil {
		fmt.Printf("* Status: Fail\n* Output:\n%v\n* Error:\n%v\n", output, err)
	} else {
		fmt.Printf("* Status: Susccess\n* Output:\n%v\n", output)
	}
}

func GetUsageStats() {
	req, _ := s3c.GetUsageStatsRequest(&s3.GetUsageStatsInput{})
	send(req)
}
