package aliyun

import (
	"bytes"
	"context"
	"crypto/md5"
	"encoding/base64"
	"encoding/xml"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"u-desk/internal/oss"
)

// ============ 生命周期相关数据结构 ============

// LifecycleStorageClass 存储类型枚举
type LifecycleStorageClass string

const (
	// StorageClassStandard 标准存储
	StorageClassStandard LifecycleStorageClass = "Standard"
	// StorageClassIA 低频存储 (Infrequent Access)
	StorageClassIA LifecycleStorageClass = "IA"
	// StorageClassArchive 归档存储
	StorageClassArchive LifecycleStorageClass = "Archive"
	// StorageClassColdArchive 冷归档存储
	StorageClassColdArchive LifecycleStorageClass = "ColdArchive"
)

// LifecycleRule 生命周期规则
type LifecycleRule struct {
	ID     string              `xml:"ID"`     // 规则 ID
	Prefix string              `xml:"Prefix"` // 前缀（应用于匹配的文件）
	Status string              `xml:"Status"` // 状态：Enabled 或 Disabled

	// Expiration 过期删除配置
	Expiration *LifecycleExpiration `xml:"Expiration,omitempty"`

	// Transition 存储类型转换配置（可以有多个）
	Transitions []LifecycleTransition `xml:"Transition,omitempty"`

	// AbortMultipartUpload 中止未完成的分片上传
	AbortMultipartUpload *LifecycleAbortMultipartUpload `xml:"AbortMultipartUpload,omitempty"`

	// Filter 过滤器（与 Prefix 二选一）
	Filter *LifecycleFilter `xml:"Filter,omitempty"`
}

// LifecycleExpiration 过期删除配置
type LifecycleExpiration struct {
	Days                      int    `xml:"Days,omitempty"`                       // 多少天后过期
	CreatedBeforeDate         string `xml:"CreatedBeforeDate,omitempty"`          // 指定日期之前创建的文件过期（格式：2023-01-01T00:00:00.000Z）
	ExpiredObjectDeleteMarker bool   `xml:"ExpiredObjectDeleteMarker,omitempty"`  // 删除过期删除标记
}

// LifecycleTransition 存储类型转换配置
type LifecycleTransition struct {
	Days            int                    `xml:"Days,omitempty"`            // 多少天后转换
	CreatedBeforeDate string               `xml:"CreatedBeforeDate,omitempty"` // 指定日期之前创建的文件转换
	StorageClass    LifecycleStorageClass `xml:"StorageClass"`               // 目标存储类型
}

// LifecycleAbortMultipartUpload 中止分片上传配置
type LifecycleAbortMultipartUpload struct {
	Days              int    `xml:"Days,omitempty"`               // 多少天后中止
	CreatedBeforeDate string `xml:"CreatedBeforeDate,omitempty"`  // 指定日期之前创建的分片上传中止
}

// LifecycleFilter 过滤器（用于更精细的规则匹配）
type LifecycleFilter struct {
	// Prefix 前缀
	Prefix string `xml:"Prefix,omitempty"`
	// Tag 标签（可以有多个）
	Tag []LifecycleTag `xml:"Tag,omitempty"`
	// Not 非匹配条件
	Not *LifecycleNotFilter `xml:"Not,omitempty"`
}

// LifecycleTag 标签
type LifecycleTag struct {
	Key   string `xml:"Key"`
	Value string `xml:"Value"`
}

// LifecycleNotFilter 非匹配条件
type LifecycleNotFilter struct {
	Prefix string        `xml:"Prefix,omitempty"`
	Tag    LifecycleTag  `xml:"Tag,omitempty"`
}

// LifecycleConfiguration 生命周期配置
type LifecycleConfiguration struct {
	XMLName xml.Name         `xml:"LifecycleConfiguration"`
	Rules   []LifecycleRule  `xml:"Rule"`
}

// ============ 生命周期管理方法 ============

// SetBucketLifecycle 设置生命周期规则
// 参考: https://help.aliyun.com/zh/oss/developer-reference/put-bucket-lifecycle
func (c *Client) SetBucketLifecycle(ctx context.Context, rules []LifecycleRule) error {
	date := time.Now().UTC().Format(http.TimeFormat)

	// 构建请求体
	config := LifecycleConfiguration{
		Rules: rules,
	}
	bodyBytes, err := xml.Marshal(config)
	if err != nil {
		return oss.NewError("LIFECYCLE_ERROR", "failed to marshal lifecycle config", err)
	}

	// 添加 XML 声明
	bodyWithHeader := []byte(xml.Header + string(bodyBytes))

	// 构建签名字符串 - 对于 bucket 级别操作，需要计算 Content-MD5
	contentType := "application/xml"
	path := "/" + c.config.Bucket + "/?lifecycle"

	// 计算 Content-MD5
	hash := md5.Sum(bodyWithHeader)
	contentMD5 := base64.StdEncoding.EncodeToString(hash[:])

	signature := c.generateSignature("PUT", path, contentType, date, contentMD5)

	scheme := "https://"
	if !c.config.UseHTTPS {
		scheme = "http://"
	}
	url := scheme + c.config.Bucket + "." + c.config.Endpoint + "/?lifecycle"

	req, err := http.NewRequestWithContext(ctx, "PUT", url, bytes.NewReader(bodyWithHeader))
	if err != nil {
		return oss.NewError("LIFECYCLE_ERROR", "failed to create request", err)
	}

	req.Header.Set("Date", date)
	req.Header.Set("Authorization", "OSS "+c.config.AccessKeyID+":"+signature)
	req.Header.Set("Content-Type", contentType)
	req.Header.Set("Content-MD5", contentMD5)

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return oss.NewError("LIFECYCLE_ERROR", "failed to set lifecycle", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		body, _ := io.ReadAll(resp.Body)
		return oss.NewError("LIFECYCLE_ERROR",
			fmt.Sprintf("set lifecycle failed with status %d: %s", resp.StatusCode, string(body)), nil)
	}

	return nil
}

// GetBucketLifecycle 获取生命周期规则
// 参考: https://help.aliyun.com/zh/oss/developer-reference/get-bucket-lifecycle
func (c *Client) GetBucketLifecycle(ctx context.Context) ([]LifecycleRule, error) {
	date := time.Now().UTC().Format(http.TimeFormat)

	// 构建签名字符串 - 使用 bucket/ 前缀
	path := "/" + c.config.Bucket + "/?lifecycle"
	signature := c.generateSignature("GET", path, "", date, "")

	scheme := "https://"
	if !c.config.UseHTTPS {
		scheme = "http://"
	}
	url := scheme + c.config.Bucket + "." + c.config.Endpoint + "/?lifecycle"

	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
	if err != nil {
		return nil, oss.NewError("LIFECYCLE_ERROR", "failed to create request", err)
	}

	req.Header.Set("Date", date)
	req.Header.Set("Authorization", "OSS "+c.config.AccessKeyID+":"+signature)

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, oss.NewError("LIFECYCLE_ERROR", "failed to get lifecycle", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, oss.NewError("LIFECYCLE_ERROR", "failed to read response", err)
	}

	if resp.StatusCode == 404 {
		// 没有设置生命周期规则
		return nil, nil
	}

	if resp.StatusCode != 200 {
		return nil, oss.NewError("LIFECYCLE_ERROR",
			fmt.Sprintf("get lifecycle failed with status %d: %s", resp.StatusCode, string(body)), nil)
	}

	// 解析 XML 响应
	var config LifecycleConfiguration
	if err := xml.Unmarshal(body, &config); err != nil {
		return nil, oss.NewError("LIFECYCLE_ERROR", "failed to parse response", err)
	}

	return config.Rules, nil
}

// DeleteBucketLifecycle 删除生命周期规则
// 参考: https://help.aliyun.com/zh/oss/developer-reference/delete-bucket-lifecycle
func (c *Client) DeleteBucketLifecycle(ctx context.Context) error {
	date := time.Now().UTC().Format(http.TimeFormat)

	// 构建签名字符串 - 使用 bucket/ 前缀
	path := "/" + c.config.Bucket + "/?lifecycle"
	signature := c.generateSignature("DELETE", path, "", date, "")

	scheme := "https://"
	if !c.config.UseHTTPS {
		scheme = "http://"
	}
	url := scheme + c.config.Bucket + "." + c.config.Endpoint + "/?lifecycle"

	req, err := http.NewRequestWithContext(ctx, "DELETE", url, nil)
	if err != nil {
		return oss.NewError("LIFECYCLE_ERROR", "failed to create request", err)
	}

	req.Header.Set("Date", date)
	req.Header.Set("Authorization", "OSS "+c.config.AccessKeyID+":"+signature)

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return oss.NewError("LIFECYCLE_ERROR", "failed to delete lifecycle", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != 204 {
		body, _ := io.ReadAll(resp.Body)
		return oss.NewError("LIFECYCLE_ERROR",
			fmt.Sprintf("delete lifecycle failed with status %d: %s", resp.StatusCode, string(body)), nil)
	}

	return nil
}

// ============ 便捷方法 ============

// SetExpirationRule 设置过期删除规则
// 为指定前缀的文件设置过期删除天数
func (c *Client) SetExpirationRule(ctx context.Context, ruleID, prefix string, days int) error {
	// 获取现有规则
	rules, err := c.GetBucketLifecycle(ctx)
	if err != nil {
		// 如果没有现有规则，创建新的规则列表
		rules = []LifecycleRule{}
	}

	// 检查是否已存在相同 ID 的规则，如果存在则更新，否则添加
	found := false
	for i, r := range rules {
		if r.ID == ruleID {
			// 更新现有规则
			rules[i].Prefix = prefix
			rules[i].Status = "Enabled"
			rules[i].Expiration = &LifecycleExpiration{Days: days}
			found = true
			break
		}
	}

	if !found {
		// 添加新规则
		rule := LifecycleRule{
			ID:     ruleID,
			Prefix: prefix,
			Status: "Enabled",
			Expiration: &LifecycleExpiration{
				Days: days,
			},
		}
		rules = append(rules, rule)
	}

	return c.SetBucketLifecycle(ctx, rules)
}

// SetTransitionRule 设置存储类型转换规则
// 为指定前缀的文件设置存储类型转换
func (c *Client) SetTransitionRule(ctx context.Context, ruleID, prefix string, days int, storageClass LifecycleStorageClass) error {
	// 获取现有规则
	rules, err := c.GetBucketLifecycle(ctx)
	if err != nil {
		// 如果没有现有规则，创建新的规则列表
		rules = []LifecycleRule{}
	}

	// 检查是否已存在相同 ID 的规则，如果存在则更新，否则添加
	found := false
	for i, r := range rules {
		if r.ID == ruleID {
			// 更新现有规则
			rules[i].Prefix = prefix
			rules[i].Status = "Enabled"
			rules[i].Transitions = []LifecycleTransition{
				{Days: days, StorageClass: storageClass},
			}
			found = true
			break
		}
	}

	if !found {
		// 添加新规则
		rule := LifecycleRule{
			ID:     ruleID,
			Prefix: prefix,
			Status: "Enabled",
			Transitions: []LifecycleTransition{
				{
					Days:         days,
					StorageClass: storageClass,
				},
			},
		}
		rules = append(rules, rule)
	}

	return c.SetBucketLifecycle(ctx, rules)
}

// SetAbortMultipartUploadRule 设置中止分片上传规则
// 为指定前缀的文件设置中止未完成的分片上传
func (c *Client) SetAbortMultipartUploadRule(ctx context.Context, ruleID, prefix string, days int) error {
	rule := LifecycleRule{
		ID:     ruleID,
		Prefix: prefix,
		Status: "Enabled",
		AbortMultipartUpload: &LifecycleAbortMultipartUpload{
			Days: days,
		},
	}
	return c.SetBucketLifecycle(ctx, []LifecycleRule{rule})
}

// SetCombinedRule 设置组合生命周期规则
// 同时支持过期删除和存储类型转换
func (c *Client) SetCombinedRule(ctx context.Context, ruleID, prefix string, expirationDays int, transitionDays int, storageClass LifecycleStorageClass) error {
	rule := LifecycleRule{
		ID:     ruleID,
		Prefix: prefix,
		Status: "Enabled",
	}

	// 设置过期删除
	if expirationDays > 0 {
		rule.Expiration = &LifecycleExpiration{
			Days: expirationDays,
		}
	}

	// 设置存储类型转换
	if transitionDays > 0 && storageClass != "" {
		rule.Transitions = []LifecycleTransition{
			{
				Days:         transitionDays,
				StorageClass: storageClass,
			},
		}
	}

	return c.SetBucketLifecycle(ctx, []LifecycleRule{rule})
}

// SetTempFileRule 设置临时文件规则
// 为临时文件目录设置规则：先转为低频存储，然后删除
func (c *Client) SetTempFileRule(ctx context.Context, prefix string, toIADays int, deleteDays int) error {
	ruleID := fmt.Sprintf("temp-files-%s", strings.ReplaceAll(prefix, "/", "-"))

	// 获取现有规则
	rules, err := c.GetBucketLifecycle(ctx)
	if err != nil {
		return err
	}

	// 创建新规则
	rule := LifecycleRule{
		ID:     ruleID,
		Prefix: prefix,
		Status: "Enabled",
	}

	// 设置存储类型转换
	if toIADays > 0 {
		rule.Transitions = []LifecycleTransition{
			{
				Days:         toIADays,
				StorageClass: StorageClassIA,
			},
		}
	}

	// 设置过期删除
	if deleteDays > 0 {
		rule.Expiration = &LifecycleExpiration{
			Days: deleteDays,
		}
	}

	// 添加到现有规则
	rules = append(rules, rule)

	return c.SetBucketLifecycle(ctx, rules)
}

// ClearTempFileRule 清除临时文件规则
func (c *Client) ClearTempFileRule(ctx context.Context, prefix string) error {
	ruleID := fmt.Sprintf("temp-files-%s", strings.ReplaceAll(prefix, "/", "-"))

	// 获取现有规则
	rules, err := c.GetBucketLifecycle(ctx)
	if err != nil {
		return err
	}

	// 过滤掉要删除的规则
	newRules := make([]LifecycleRule, 0, len(rules))
	for _, rule := range rules {
		if rule.ID != ruleID {
			newRules = append(newRules, rule)
		}
	}

	// 更新规则
	if len(newRules) == 0 {
		return c.DeleteBucketLifecycle(ctx)
	}

	return c.SetBucketLifecycle(ctx, newRules)
}

// ListLifecycleRules 列出所有生命周期规则（带详细信息）
func (c *Client) ListLifecycleRules(ctx context.Context) ([]LifecycleRule, error) {
	return c.GetBucketLifecycle(ctx)
}

// DisableLifecycleRule 禁用生命周期规则
func (c *Client) DisableLifecycleRule(ctx context.Context, ruleID string) error {
	rules, err := c.GetBucketLifecycle(ctx)
	if err != nil {
		return err
	}

	// 找到并禁用规则
	found := false
	for i := range rules {
		if rules[i].ID == ruleID {
			rules[i].Status = "Disabled"
			found = true
			break
		}
	}

	if !found {
		return oss.NewError("LIFECYCLE_ERROR", "rule not found: "+ruleID, nil)
	}

	return c.SetBucketLifecycle(ctx, rules)
}

// EnableLifecycleRule 启用生命周期规则
func (c *Client) EnableLifecycleRule(ctx context.Context, ruleID string) error {
	rules, err := c.GetBucketLifecycle(ctx)
	if err != nil {
		return err
	}

	// 找到并启用规则
	found := false
	for i := range rules {
		if rules[i].ID == ruleID {
			rules[i].Status = "Enabled"
			found = true
			break
		}
	}

	if !found {
		return oss.NewError("LIFECYCLE_ERROR", "rule not found: "+ruleID, nil)
	}

	return c.SetBucketLifecycle(ctx, rules)
}

// DeleteLifecycleRule 删除生命周期规则
func (c *Client) DeleteLifecycleRule(ctx context.Context, ruleID string) error {
	rules, err := c.GetBucketLifecycle(ctx)
	if err != nil {
		return err
	}

	// 过滤掉要删除的规则
	newRules := make([]LifecycleRule, 0, len(rules))
	for _, rule := range rules {
		if rule.ID != ruleID {
			newRules = append(newRules, rule)
		}
	}

	// 更新规则
	if len(newRules) == 0 {
		return c.DeleteBucketLifecycle(ctx)
	}

	return c.SetBucketLifecycle(ctx, newRules)
}
