package oss

import (
	"encoding/xml"
	"net/url"
	"time"
)

// ListBucketsResult ListBuckets请求返回的结果
type ListBucketsResult struct {
	XMLName     xml.Name           `xml:"ListAllMyBucketsResult"`
	Prefix      string             `xml:"Prefix"`         // 本次查询结果的前缀
	Marker      string             `xml:"Marker"`         // 标明查询的起点，未全部返回时有此节点
	MaxKeys     int                `xml:"MaxKeys"`        // 返回结果的最大数目，未全部返回时有此节点
	IsTruncated bool               `xml:"IsTruncated"`    // 所有的结果是否已经全部返回
	NextMarker  string             `xml:"NextMarker"`     // 表示下一次查询的起点
	Owner       Owner              `xml:"Owner"`          // 拥有者信息
	Buckets     []BucketProperties `xml:"Buckets>Bucket"` // Bucket列表
}

// BucketProperties Bucket信息
type BucketProperties struct {
	XMLName      xml.Name  `xml:"Bucket"`
	Name         string    `xml:"Name"`         // Bucket名称
	Location     string    `xml:"Location"`     // Bucket所在的数据中心
	CreationDate time.Time `xml:"CreationDate"` // Bucket创建时间
}

// GetBucketACLResult GetBucketACL请求返回的结果
type GetBucketACLResult struct {
	XMLName xml.Name `xml:"AccessControlPolicy"`
	ACL     string   `xml:"AccessControlList>Grant"` // Bucket权限
	Owner   Owner    `xml:"Owner"`                   // Bucket拥有者信息
}

// LifecycleConfiguration Bucket的Lifecycle配置
type LifecycleConfiguration struct {
	XMLName xml.Name        `xml:"LifecycleConfiguration"`
	Rules   []LifecycleRule `xml:"Rule"`
}

// LifecycleRule Lifecycle规则
type LifecycleRule struct {
	XMLName    xml.Name            `xml:"Rule"`
	ID         string              `xml:"ID"`         // 规则唯一的ID
	Prefix     string              `xml:"Prefix"`     // 规则所适用Object的前缀
	Status     string              `xml:"Status"`     // 规则是否生效
	Expiration LifecycleExpiration `xml:"Expiration"` // 规则的过期属性
}

// LifecycleExpiration 规则的过期属性
type LifecycleExpiration struct {
	XMLName xml.Name  `xml:"Expiration"`
	Days    int       `xml:"Days,omitempty"` // 最后修改时间过后多少天生效
	Date    time.Time `xml:"Date,omitempty"` // 指定规则何时生效
}

type lifecycleXML struct {
	XMLName xml.Name        `xml:"LifecycleConfiguration"`
	Rules   []lifecycleRule `xml:"Rule"`
}

type lifecycleRule struct {
	XMLName    xml.Name            `xml:"Rule"`
	ID         string              `xml:"ID"`
	Prefix     string              `xml:"Prefix"`
	Status     string              `xml:"Status"`
	Expiration lifecycleExpiration `xml:"Expiration"`
}

type lifecycleExpiration struct {
	XMLName xml.Name `xml:"Expiration"`
	Days    int      `xml:"Days,omitempty"`
	Date    string   `xml:"Date,omitempty"`
}

const expirationDateFormat = "2006-01-02T15:04:05.000Z"

func convLifecycleRule(rules []LifecycleRule) []lifecycleRule {
	rs := []lifecycleRule{}
	for _, rule := range rules {
		r := lifecycleRule{}
		r.ID = rule.ID
		r.Prefix = rule.Prefix
		r.Status = rule.Status
		if rule.Expiration.Date.IsZero() {
			r.Expiration.Days = rule.Expiration.Days
		} else {
			r.Expiration.Date = rule.Expiration.Date.Format(expirationDateFormat)
		}
		rs = append(rs, r)
	}
	return rs
}

// BuildLifecycleRuleByDays 指定过期天数构建Lifecycle规则
func BuildLifecycleRuleByDays(id, prefix string, status bool, days int) LifecycleRule {
	var statusStr = "Enabled"
	if !status {
		statusStr = "Disabled"
	}
	return LifecycleRule{ID: id, Prefix: prefix, Status: statusStr,
		Expiration: LifecycleExpiration{Days: days}}
}

// BuildLifecycleRuleByDate 指定过期时间构建Lifecycle规则
func BuildLifecycleRuleByDate(id, prefix string, status bool, year, month, day int) LifecycleRule {
	var statusStr = "Enabled"
	if !status {
		statusStr = "Disabled"
	}
	date := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
	return LifecycleRule{ID: id, Prefix: prefix, Status: statusStr,
		Expiration: LifecycleExpiration{Date: date}}
}

// GetBucketLifecycleResult GetBucketLifecycle请求请求结果
type GetBucketLifecycleResult LifecycleConfiguration

// RefererXML Referer配置
type RefererXML struct {
	XMLName           xml.Name `xml:"RefererConfiguration"`
	AllowEmptyReferer bool     `xml:"AllowEmptyReferer"`   // 是否允许referer字段为空的请求访问
	RefererList       []string `xml:"RefererList>Referer"` // referer访问白名单
}

// GetBucketRefererResult GetBucketReferer请教返回结果
type GetBucketRefererResult RefererXML

// LoggingXML Logging配置
type LoggingXML struct {
	XMLName        xml.Name       `xml:"BucketLoggingStatus"`
	LoggingEnabled LoggingEnabled `xml:"LoggingEnabled"` // 访问日志信息容器
}

type loggingXMLEmpty struct {
	XMLName xml.Name `xml:"BucketLoggingStatus"`
}

// LoggingEnabled 访问日志信息容器
type LoggingEnabled struct {
	XMLName      xml.Name `xml:"LoggingEnabled"`
	TargetBucket string   `xml:"TargetBucket"` //存放访问日志的Bucket
	TargetPrefix string   `xml:"TargetPrefix"` //保存访问日志的文件前缀
}

// GetBucketLoggingResult GetBucketLogging请求返回结果
type GetBucketLoggingResult LoggingXML

// WebsiteXML Website配置
type WebsiteXML struct {
	XMLName       xml.Name      `xml:"WebsiteConfiguration"`
	IndexDocument IndexDocument `xml:"IndexDocument"` // 目录URL时添加的索引文件
	ErrorDocument ErrorDocument `xml:"ErrorDocument"` // 404错误时使用的文件
}

// IndexDocument 目录URL时添加的索引文件
type IndexDocument struct {
	XMLName xml.Name `xml:"IndexDocument"`
	Suffix  string   `xml:"Suffix"` // 目录URL时添加的索引文件名
}

// ErrorDocument 404错误时使用的文件
type ErrorDocument struct {
	XMLName xml.Name `xml:"ErrorDocument"`
	Key     string   `xml:"Key"` // 404错误时使用的文件名
}

// GetBucketWebsiteResult GetBucketWebsite请求返回结果
type GetBucketWebsiteResult WebsiteXML

// CORSXML CORS配置
type CORSXML struct {
	XMLName   xml.Name   `xml:"CORSConfiguration"`
	CORSRules []CORSRule `xml:"CORSRule"` // CORS规则列表
}

// CORSRule CORS规则
type CORSRule struct {
	XMLName       xml.Name `xml:"CORSRule"`
	AllowedOrigin []string `xml:"AllowedOrigin"` // 允许的来源，默认通配符"*"
	AllowedMethod []string `xml:"AllowedMethod"` // 允许的方法
	AllowedHeader []string `xml:"AllowedHeader"` // 允许的请求头
	ExposeHeader  []string `xml:"ExposeHeader"`  // 允许的响应头
	MaxAgeSeconds int      `xml:"MaxAgeSeconds"` // 最大的缓存时间
}

// GetBucketCORSResult GetBucketCORS请求返回的结果
type GetBucketCORSResult CORSXML

// GetBucketInfoResult GetBucketInfo请求返回结果
type GetBucketInfoResult struct {
	XMLName        xml.Name `xml:"BucketInfo"`
	BucketInfo     BucketInfo   `xml:"Bucket"`
}

// BucketInfo Bucket信息
type BucketInfo struct {
	XMLName          xml.Name  `xml:"Bucket"`
	Name             string    `xml:"Name"`                    // Bucket名称
	Location         string    `xml:"Location"`                // Bucket所在的数据中心
	CreationDate     time.Time `xml:"CreationDate"`            // Bucket创建时间
	ExtranetEndpoint string    `xml:"ExtranetEndpoint"`        // Bucket访问的外网域名 
	IntranetEndpoint string    `xml:"IntranetEndpoint"`        // Bucket访问的内网域名
	ACL              string    `xml:"AccessControlList>Grant"` // Bucket权限
	Owner            Owner     `xml:"Owner"`                   // Bucket拥有者信息
}

// ListObjectsResult ListObjects请求返回结果
type ListObjectsResult struct {
	XMLName        xml.Name           `xml:"ListBucketResult"`
	Prefix         string             `xml:"Prefix"`                // 本次查询结果的开始前缀
	Marker         string             `xml:"Marker"`                // 这次查询的起点
	MaxKeys        int                `xml:"MaxKeys"`               // 请求返回结果的最大数目
	Delimiter      string             `xml:"Delimiter"`             // 对Object名字进行分组的字符
	IsTruncated    bool               `xml:"IsTruncated"`           // 是否所有的结果都已经返回
	NextMarker     string             `xml:"NextMarker"`            // 下一次查询的起点
	Objects        []ObjectProperties `xml:"Contents"`              // Object类别
	CommonPrefixes []string           `xml:"CommonPrefixes>Prefix"` // 以delimiter结尾并有共同前缀的Object的集合
}

// ObjectProperties Objecct属性
type ObjectProperties struct {
	XMLName      xml.Name  `xml:"Contents"`
	Key          string    `xml:"Key"`          // Object的Key
	Type         string    `xml:"Type"`         // Object Type
	Size         int64     `xml:"Size"`         // Object的长度字节数
	ETag         string    `xml:"ETag"`         // 标示Object的内容
	Owner        Owner     `xml:"Owner"`        // 保存Object拥有者信息的容器
	LastModified time.Time `xml:"LastModified"` // Object最后修改时间
	StorageClass string    `xml:"StorageClass"` // Object的存储类型，目前只能是Standard
}

// Owner Bucket/Object的owner
type Owner struct {
	XMLName     xml.Name `xml:"Owner"`
	ID          string   `xml:"ID"`          // 用户ID
	DisplayName string   `xml:"DisplayName"` // Owner名字
}

// CopyObjectResult CopyObject请求返回的结果
type CopyObjectResult struct {
	XMLName      xml.Name  `xml:"CopyObjectResult"`
	LastModified time.Time `xml:"LastModified"` // 新Object最后更新时间
	ETag         string    `xml:"ETag"`         // 新Object的ETag值
}

// GetObjectACLResult GetObjectACL请求返回的结果
type GetObjectACLResult GetBucketACLResult

type deleteXML struct {
	XMLName xml.Name       `xml:"Delete"`
	Objects []DeleteObject `xml:"Object"` // 删除的所有Object
	Quiet   bool           `xml:"Quiet"`  // 安静响应模式
}

// DeleteObject 删除的Object
type DeleteObject struct {
	XMLName xml.Name `xml:"Object"`
	Key     string   `xml:"Key"` // Object名称
}

// DeleteObjectsResult DeleteObjects请求返回结果
type DeleteObjectsResult struct {
	XMLName        xml.Name `xml:"DeleteResult"`
	DeletedObjects []string `xml:"Deleted>Key"` // 删除的Object列表
}

// InitiateMultipartUploadResult InitiateMultipartUpload请求返回结果
type InitiateMultipartUploadResult struct {
	XMLName  xml.Name `xml:"InitiateMultipartUploadResult"`
	Bucket   string   `xml:"Bucket"`   // Bucket名称
	Key      string   `xml:"Key"`      // 上传Object名称
	UploadID string   `xml:"UploadId"` // 生成的UploadId
}

// UploadPart 上传/拷贝的分片
type UploadPart struct {
	XMLName    xml.Name `xml:"Part"`
	PartNumber int      `xml:"PartNumber"` // Part编号
	ETag       string   `xml:"ETag"`       // ETag缓存码
}

type uploadParts []UploadPart

func (slice uploadParts) Len() int {
	return len(slice)
}

func (slice uploadParts) Less(i, j int) bool {
	return slice[i].PartNumber < slice[j].PartNumber
}

func (slice uploadParts) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

// UploadPartCopyResult 拷贝分片请求返回的结果
type UploadPartCopyResult struct {
	XMLName      xml.Name  `xml:"CopyPartResult"`
	LastModified time.Time `xml:"LastModified"` // 最后修改时间
	ETag         string    `xml:"ETag"`         // ETag
}

type completeMultipartUploadXML struct {
	XMLName xml.Name     `xml:"CompleteMultipartUpload"`
	Part    []UploadPart `xml:"Part"`
}

// CompleteMultipartUploadResult 提交分片上传任务返回结果
type CompleteMultipartUploadResult struct {
	XMLName  xml.Name `xml:"CompleteMultipartUploadResult"`
	Location string   `xml:"Location"` // Object的URL
	Bucket   string   `xml:"Bucket"`   // Bucket名称
	ETag     string   `xml:"ETag"`     // Object的ETag
	Key      string   `xml:"Key"`      // Object的名字
}

// ListUploadedPartsResult ListUploadedParts请求返回结果
type ListUploadedPartsResult struct {
	XMLName              xml.Name       `xml:"ListPartsResult"`
	Bucket               string         `xml:"Bucket"`               // Bucket名称
	Key                  string         `xml:"Key"`                  // Object名称
	UploadID             string         `xml:"UploadId"`             // 上传Id
	NextPartNumberMarker string         `xml:"NextPartNumberMarker"` // 下一个Part的位置
	MaxParts             int            `xml:"MaxParts"`             // 最大Part个数
	IsTruncated          bool           `xml:"IsTruncated"`          // 是否完全上传完成
	UploadedParts        []UploadedPart `xml:"Part"`                 // 已完成的Part
}

// UploadedPart 该任务已经上传的分片
type UploadedPart struct {
	XMLName      xml.Name  `xml:"Part"`
	PartNumber   int       `xml:"PartNumber"`   // Part编号
	LastModified time.Time `xml:"LastModified"` // 最后一次修改时间
	ETag         string    `xml:"ETag"`         // ETag缓存码
	Size         int       `xml:"Size"`         // Part大小
}

// ListMultipartUploadResult ListMultipartUpload请求返回结果
type ListMultipartUploadResult struct {
	XMLName            xml.Name            `xml:"ListMultipartUploadsResult"`
	Bucket             string              `xml:"Bucket"`                // Bucket名称
	Delimiter          string              `xml:"Delimiter"`             // 分组分割符
	Prefix             string              `xml:"Prefix"`                // 筛选前缀
	KeyMarker          string              `xml:"KeyMarker"`             // 起始Object位置
	UploadIDMarker     string              `xml:"UploadIdMarker"`        // 起始UploadId位置
	NextKeyMarker      string              `xml:"NextKeyMarker"`         // 如果没有全部返回，标明接下去的KeyMarker位置
	NextUploadIDMarker string              `xml:"NextUploadIdMarker"`    // 如果没有全部返回，标明接下去的UploadId位置
	MaxUploads         int                 `xml:"MaxUploads"`            // 返回最大Upload数目
	IsTruncated        bool                `xml:"IsTruncated"`           // 是否完全返回
	Uploads            []UncompletedUpload `xml:"Upload"`                // 未完成上传的MultipartUpload
	CommonPrefixes     []string            `xml:"CommonPrefixes>Prefix"` // 所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组的分组结果
}

// UncompletedUpload 未完成的Upload任务
type UncompletedUpload struct {
	XMLName   xml.Name  `xml:"Upload"`
	Key       string    `xml:"Key"`       // Object名称
	UploadID  string    `xml:"UploadId"`  // 对应UploadId
	Initiated time.Time `xml:"Initiated"` // 初始化时间，格式2012-02-23T04:18:23.000Z
}

// 解析URL编码
func decodeDeleteObjectsResult(result *DeleteObjectsResult) error {
	var err error
	for i := 0; i < len(result.DeletedObjects); i++ {
		result.DeletedObjects[i], err = url.QueryUnescape(result.DeletedObjects[i])
		if err != nil {
			return err
		}
	}
	return nil
}

// 解析URL编码
func decodeListObjectsResult(result *ListObjectsResult) error {
	var err error
	result.Prefix, err = url.QueryUnescape(result.Prefix)
	if err != nil {
		return err
	}
	result.Marker, err = url.QueryUnescape(result.Marker)
	if err != nil {
		return err
	}
	result.Delimiter, err = url.QueryUnescape(result.Delimiter)
	if err != nil {
		return err
	}
	result.NextMarker, err = url.QueryUnescape(result.NextMarker)
	if err != nil {
		return err
	}
	for i := 0; i < len(result.Objects); i++ {
		result.Objects[i].Key, err = url.QueryUnescape(result.Objects[i].Key)
		if err != nil {
			return err
		}
	}
	for i := 0; i < len(result.CommonPrefixes); i++ {
		result.CommonPrefixes[i], err = url.QueryUnescape(result.CommonPrefixes[i])
		if err != nil {
			return err
		}
	}
	return nil
}

// 解析URL编码
func decodeListMultipartUploadResult(result *ListMultipartUploadResult) error {
	var err error
	result.Prefix, err = url.QueryUnescape(result.Prefix)
	if err != nil {
		return err
	}
	result.Delimiter, err = url.QueryUnescape(result.Delimiter)
	if err != nil {
		return err
	}
	result.KeyMarker, err = url.QueryUnescape(result.KeyMarker)
	if err != nil {
		return err
	}
	result.NextKeyMarker, err = url.QueryUnescape(result.NextKeyMarker)
	if err != nil {
		return err
	}
	for i := 0; i < len(result.Uploads); i++ {
		result.Uploads[i].Key, err = url.QueryUnescape(result.Uploads[i].Key)
		if err != nil {
			return err
		}
	}
	for i := 0; i < len(result.CommonPrefixes); i++ {
		result.CommonPrefixes[i], err = url.QueryUnescape(result.CommonPrefixes[i])
		if err != nil {
			return err
		}
	}
	return nil
}
