package aliyunwaf

import (
	"context"
	"fmt"
	"log/slog"
	"strings"
	"time"

	aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	"github.com/alibabacloud-go/tea/dara"
	"github.com/alibabacloud-go/tea/tea"
	"github.com/samber/lo"

	aliwaf "github.com/certimate-go/certimate/pkg/sdk3rd-trimmed/github.com/alibabacloud-go/waf-openapi-20211001/v7/client"

	"github.com/certimate-go/certimate/pkg/core"
	cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/aliyun-cas"
	xalibabacloud "github.com/certimate-go/certimate/pkg/utils/third-party/alibabacloud"
)

type (
	Provider     = core.Deployer
	DeployResult = core.DeployerDeployResult
)

type DeployerConfig struct {
	// 阿里云 AccessKeyId。
	AccessKeyId string `json:"accessKeyId"`
	// 阿里云 AccessKeySecret。
	AccessKeySecret string `json:"accessKeySecret"`
	// 阿里云资源组 ID。
	ResourceGroupId string `json:"resourceGroupId,omitempty"`
	// 阿里云地域。
	Region string `json:"region"`
	// 服务版本。
	// 可取值 "3.0"。
	ServiceVersion string `json:"serviceVersion"`
	// 服务类型。
	ServiceType string `json:"serviceType"`
	// WAF 实例 ID。
	InstanceId string `json:"instanceId"`
	// 云产品类型。
	// 服务类型为 [SERVICE_TYPE_CLOUDRESOURCE] 时必填。
	ResourceProduct string `json:"resourceProduct,omitempty"`
	// 云产品资源 ID。
	// 服务类型为 [SERVICE_TYPE_CLOUDRESOURCE] 时必填。
	ResourceId string `json:"resourceId,omitempty"`
	// 云产品资源端口。
	// 服务类型为 [SERVICE_TYPE_CLOUDRESOURCE] 时必填。
	ResourcePort int32 `json:"resourcePort,omitempty"`
	// 扩展域名（支持泛域名）。
	Domain string `json:"domain,omitempty"`
}

type Deployer struct {
	config     *DeployerConfig
	logger     *slog.Logger
	sdkClient  *aliwaf.Client
	sdkCertmgr core.Certmgr
}

var _ Provider = (*Deployer)(nil)

func NewDeployer(config *DeployerConfig) (*Deployer, error) {
	if config == nil {
		return nil, fmt.Errorf("the configuration of the deployer provider is nil")
	}

	client, err := createSDKClient(config.AccessKeyId, config.AccessKeySecret, config.Region)
	if err != nil {
		return nil, fmt.Errorf("could not create client: %w", err)
	}

	pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
		AccessKeyId:     config.AccessKeyId,
		AccessKeySecret: config.AccessKeySecret,
		ResourceGroupId: config.ResourceGroupId,
		Region:          lo.Ternary(xalibabacloud.IsIntlRegion(config.Region), "ap-southeast-1", ""),
	})
	if err != nil {
		return nil, fmt.Errorf("could not create certmgr: %w", err)
	}

	return &Deployer{
		config:     config,
		logger:     slog.Default(),
		sdkClient:  client,
		sdkCertmgr: pcertmgr,
	}, nil
}

func (d *Deployer) SetLogger(logger *slog.Logger) {
	if logger == nil {
		d.logger = slog.New(slog.DiscardHandler)
	} else {
		d.logger = logger
	}

	d.sdkCertmgr.SetLogger(logger)
}

func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
	switch d.config.ServiceVersion {
	case "3", "3.0":
		if err := d.deployToWAF3(ctx, certPEM, privkeyPEM); err != nil {
			return nil, err
		}

	default:
		return nil, fmt.Errorf("unsupported service version '%s'", d.config.ServiceVersion)
	}

	return &DeployResult{}, nil
}

func (d *Deployer) deployToWAF3(ctx context.Context, certPEM, privkeyPEM string) error {
	if d.config.InstanceId == "" {
		return fmt.Errorf("config `instanceId` is required")
	}

	// 上传证书
	upres, err := d.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
	if err != nil {
		return fmt.Errorf("failed to upload certificate file: %w", err)
	} else {
		d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
	}

	// 根据接入方式决定部署方式
	switch d.config.ServiceType {
	case SERVICE_TYPE_CLOUDRESOURCE:
		certId := upres.ExtendedData["CertIdWithRegion"].(string)
		if err := d.deployToWAF3WithCloudResource(ctx, certId); err != nil {
			return err
		}

	case SERVICE_TYPE_CNAME:
		certId := upres.ExtendedData["CertIdWithRegion"].(string)
		if err := d.deployToWAF3WithCNAME(ctx, certId); err != nil {
			return err
		}

	default:
		return fmt.Errorf("unsupported service version '%s'", d.config.ServiceVersion)
	}

	return nil
}

func (d *Deployer) deployToWAF3WithCloudResource(ctx context.Context, cloudCertId string) error {
	if d.config.ResourceProduct == "" {
		return fmt.Errorf("config `resourceProduct` is required")
	}
	if d.config.ResourceId == "" {
		return fmt.Errorf("config `resourceId` is required")
	}
	if d.config.ResourcePort == 0 {
		return fmt.Errorf("config `resourcePort` is required")
	}

	// 查询云产品实例已同步的证书列表
	// REF: https://www.alibabacloud.com/help/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-describeresourceinstancecerts
	//
	// 注意，虽然文档中描述为分页查询，但实际调用不支持分页
	// https://github.com/certimate-go/certimate/issues/1122
	var wafResourceInstanceCertificates []*aliwaf.DescribeResourceInstanceCertsResponseBodyCerts
	describeResourceInstanceCertsReq := &aliwaf.DescribeResourceInstanceCertsRequest{
		RegionId:                       tea.String(d.config.Region),
		ResourceManagerResourceGroupId: lo.EmptyableToPtr(d.config.ResourceGroupId),
		InstanceId:                     tea.String(d.config.InstanceId),
		ResourceInstanceId:             tea.String(d.config.ResourceId),
	}
	describeResourceInstanceCertsResp, err := d.sdkClient.DescribeResourceInstanceCertsWithContext(ctx, describeResourceInstanceCertsReq, &dara.RuntimeOptions{})
	d.logger.Debug("sdk request 'waf.DescribeResourceInstanceCerts'", slog.Any("request", describeResourceInstanceCertsReq), slog.Any("response", describeResourceInstanceCertsResp))
	if err != nil {
		return fmt.Errorf("failed to execute sdk request 'waf.DescribeResourceInstanceCerts': %w", err)
	} else {
		wafResourceInstanceCertificates = describeResourceInstanceCertsResp.Body.Certs
	}

	// 获取云产品实例的接入端口详情
	// REF: https://www.alibabacloud.com/help/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-describecloudresourceaccessportdetails
	var wafCloudResourceCloudAccessPort *aliwaf.DescribeCloudResourceAccessPortDetailsResponseBodyAccessPortDetails
	var wafCloudResourceCertificates []*aliwaf.DescribeCloudResourceAccessPortDetailsResponseBodyAccessPortDetailsCertificates
	describeCloudResourceAccessPortDetailsRequest := &aliwaf.DescribeCloudResourceAccessPortDetailsRequest{
		RegionId:                       tea.String(d.config.Region),
		ResourceManagerResourceGroupId: lo.EmptyableToPtr(d.config.ResourceGroupId),
		InstanceId:                     tea.String(d.config.InstanceId),
		ResourceInstanceId:             tea.String(d.config.ResourceId),
		Port:                           tea.String(fmt.Sprintf("%d", d.config.ResourcePort)),
	}
	describeCloudResourceAccessPortDetailsResponse, err := d.sdkClient.DescribeCloudResourceAccessPortDetailsWithContext(ctx, describeCloudResourceAccessPortDetailsRequest, &dara.RuntimeOptions{})
	d.logger.Debug("sdk request 'waf.DescribeCloudResourceAccessPortDetails'", slog.Any("request", describeCloudResourceAccessPortDetailsRequest), slog.Any("response", describeCloudResourceAccessPortDetailsResponse))
	if err != nil {
		return fmt.Errorf("failed to execute sdk request 'waf.DescribeCloudResourceAccessPortDetails': %w", err)
	} else if len(describeCloudResourceAccessPortDetailsResponse.Body.AccessPortDetails) == 0 {
		return fmt.Errorf("could not get access port details of waf '%s' cloud resource '%s %s:%d'", d.config.InstanceId, d.config.ResourceProduct, d.config.ResourceId, d.config.ResourcePort)
	} else {
		wafCloudResourceCloudAccessPort = describeCloudResourceAccessPortDetailsResponse.Body.AccessPortDetails[0]
		wafCloudResourceCertificates = wafCloudResourceCloudAccessPort.Certificates
		if len(wafCloudResourceCertificates) == 0 {
			return fmt.Errorf("could not get access port certificates of waf '%s' cloud resource '%s %s:%d'", d.config.InstanceId, d.config.ResourceProduct, d.config.ResourceId, d.config.ResourcePort)
		}
	}

	// 生成请求参数
	modifyCloudResourceCertReq := &aliwaf.ModifyCloudResourceCertRequest{
		RegionId:        tea.String(d.config.Region),
		InstanceId:      tea.String(d.config.InstanceId),
		CloudResourceId: wafCloudResourceCloudAccessPort.CloudResourceId,
	}
	if d.config.Domain == "" {
		// 未指定扩展域名，只需替换默认证书
		const certAppliedTypeDefault = "default"

		// 已部署过，直接返回
		for _, certItem := range wafCloudResourceCertificates {
			if tea.StringValue(certItem.AppliedType) == certAppliedTypeDefault &&
				tea.StringValue(certItem.CertificateId) == cloudCertId {
				d.logger.Info("no need to deploy waf default certificate")
				return nil
			}
		}

		// 移除原默认证书，添加新默认证书
		modifyCloudResourceCertReq.Certificates = lo.Map(wafCloudResourceCertificates, func(c *aliwaf.DescribeCloudResourceAccessPortDetailsResponseBodyAccessPortDetailsCertificates, _ int) *aliwaf.ModifyCloudResourceCertRequestCertificates {
			return &aliwaf.ModifyCloudResourceCertRequestCertificates{
				CertificateId: c.CertificateId,
				AppliedType:   c.AppliedType,
			}
		})
		modifyCloudResourceCertReq.Certificates = lo.Filter(modifyCloudResourceCertReq.Certificates, func(c *aliwaf.ModifyCloudResourceCertRequestCertificates, _ int) bool {
			if tea.StringValue(c.AppliedType) == certAppliedTypeDefault {
				return false
			}

			return true
		})
		modifyCloudResourceCertReq.Certificates = append(modifyCloudResourceCertReq.Certificates, &aliwaf.ModifyCloudResourceCertRequestCertificates{
			CertificateId: tea.String(cloudCertId),
			AppliedType:   tea.String(certAppliedTypeDefault),
		})
	} else {
		// 指定扩展域名，替换或新增扩展证书
		const certAppliedTypeExtension = "extension"

		// 已部署过，直接返回
		for _, certItem := range wafCloudResourceCertificates {
			if tea.StringValue(certItem.AppliedType) == certAppliedTypeExtension &&
				tea.StringValue(certItem.CertificateId) == cloudCertId {
				d.logger.Info("no need to deploy waf extension certificate")
				return nil
			}
		}

		// 移除同 CommonName 的原扩展证书，添加新扩展证书
		modifyCloudResourceCertReq.Certificates = lo.Map(wafCloudResourceCertificates, func(c *aliwaf.DescribeCloudResourceAccessPortDetailsResponseBodyAccessPortDetailsCertificates, _ int) *aliwaf.ModifyCloudResourceCertRequestCertificates {
			return &aliwaf.ModifyCloudResourceCertRequestCertificates{
				CertificateId: c.CertificateId,
				AppliedType:   c.AppliedType,
			}
		})
		modifyCloudResourceCertReq.Certificates = lo.Filter(modifyCloudResourceCertReq.Certificates, func(c *aliwaf.ModifyCloudResourceCertRequestCertificates, _ int) bool {
			if tea.StringValue(c.AppliedType) == certAppliedTypeExtension {
				if tea.StringValue(c.CertificateId) == cloudCertId {
					return false
				}

				var certCommonName string
				for _, r := range wafResourceInstanceCertificates {
					if tea.StringValue(c.CertificateId) == tea.StringValue(r.CertIdentifier) {
						certCommonName = tea.StringValue(r.CommonName)
						break
					}
				}
				if certCommonName == d.config.Domain {
					return false
				}
			}

			return true
		})
		modifyCloudResourceCertReq.Certificates = append(modifyCloudResourceCertReq.Certificates, &aliwaf.ModifyCloudResourceCertRequestCertificates{
			CertificateId: tea.String(cloudCertId),
			AppliedType:   tea.String(certAppliedTypeExtension),
		})
	}

	// 过滤掉不存在或已过期的证书，防止接口报错
	modifyCloudResourceCertReq.Certificates = lo.Filter(modifyCloudResourceCertReq.Certificates, func(c *aliwaf.ModifyCloudResourceCertRequestCertificates, _ int) bool {
		if tea.StringValue(c.CertificateId) == cloudCertId {
			return true
		}

		resourceInstanceCert, _ := lo.Find(wafResourceInstanceCertificates, func(r *aliwaf.DescribeResourceInstanceCertsResponseBodyCerts) bool {
			cId := tea.StringValue(c.CertificateId)
			rId := tea.StringValue(r.CertIdentifier)
			return cId == rId || strings.Split(cId, "-")[0] == strings.Split(rId, "-")[0]
		})
		if resourceInstanceCert != nil {
			certNotAfter := time.Unix(tea.Int64Value(resourceInstanceCert.AfterDate)/1000, 0)
			return certNotAfter.After(time.Now())
		}

		return false
	})

	// 修改云产品接入的证书
	// REF: https://www.alibabacloud.com/help/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-modifycloudresourcecert
	modifyCloudResourceCertResp, err := d.sdkClient.ModifyCloudResourceCertWithContext(ctx, modifyCloudResourceCertReq, &dara.RuntimeOptions{})
	d.logger.Debug("sdk request 'waf.ModifyCloudResourceCert'", slog.Any("request", modifyCloudResourceCertReq), slog.Any("response", modifyCloudResourceCertResp))
	if err != nil {
		return fmt.Errorf("failed to execute sdk request 'waf.ModifyCloudResourceCert': %w", err)
	}

	return nil
}

func (d *Deployer) deployToWAF3WithCNAME(ctx context.Context, cloudCertId string) error {
	if d.config.Domain == "" {
		// 未指定扩展域名，只需替换默认证书

		// 查询默认 SSL/TLS 设置
		// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-describedefaulthttps
		describeDefaultHttpsReq := &aliwaf.DescribeDefaultHttpsRequest{
			ResourceManagerResourceGroupId: lo.EmptyableToPtr(d.config.ResourceGroupId),
			RegionId:                       tea.String(d.config.Region),
			InstanceId:                     tea.String(d.config.InstanceId),
		}
		describeDefaultHttpsResp, err := d.sdkClient.DescribeDefaultHttpsWithContext(ctx, describeDefaultHttpsReq, &dara.RuntimeOptions{})
		d.logger.Debug("sdk request 'waf.DescribeDefaultHttps'", slog.Any("request", describeDefaultHttpsReq), slog.Any("response", describeDefaultHttpsResp))
		if err != nil {
			return fmt.Errorf("failed to execute sdk request 'waf.DescribeDefaultHttps': %w", err)
		}

		// 修改默认 SSL/TLS 设置
		// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-modifydefaulthttps
		modifyDefaultHttpsReq := &aliwaf.ModifyDefaultHttpsRequest{
			ResourceManagerResourceGroupId: lo.EmptyableToPtr(d.config.ResourceGroupId),
			RegionId:                       tea.String(d.config.Region),
			InstanceId:                     tea.String(d.config.InstanceId),
			CertId:                         tea.String(cloudCertId),
			TLSVersion:                     tea.String("tlsv1.2"),
			EnableTLSv3:                    tea.Bool(true),
		}
		if describeDefaultHttpsResp.Body != nil && describeDefaultHttpsResp.Body.DefaultHttps != nil {
			if describeDefaultHttpsResp.Body.DefaultHttps.TLSVersion != nil {
				modifyDefaultHttpsReq.TLSVersion = describeDefaultHttpsResp.Body.DefaultHttps.TLSVersion
			}
			if describeDefaultHttpsResp.Body.DefaultHttps.EnableTLSv3 == nil {
				modifyDefaultHttpsReq.EnableTLSv3 = describeDefaultHttpsResp.Body.DefaultHttps.EnableTLSv3
			}
		}
		modifyDefaultHttpsResp, err := d.sdkClient.ModifyDefaultHttpsWithContext(ctx, modifyDefaultHttpsReq, &dara.RuntimeOptions{})
		d.logger.Debug("sdk request 'waf.ModifyDefaultHttps'", slog.Any("request", modifyDefaultHttpsReq), slog.Any("response", modifyDefaultHttpsResp))
		if err != nil {
			return fmt.Errorf("failed to execute sdk request 'waf.ModifyDefaultHttps': %w", err)
		}
	} else {
		// 指定扩展域名，需替换扩展证书

		// 查询 CNAME 接入详情
		// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-describedomaindetail
		describeDomainDetailReq := &aliwaf.DescribeDomainDetailRequest{
			RegionId:   tea.String(d.config.Region),
			InstanceId: tea.String(d.config.InstanceId),
			Domain:     tea.String(d.config.Domain),
		}
		describeDomainDetailResp, err := d.sdkClient.DescribeDomainDetailWithContext(ctx, describeDomainDetailReq, &dara.RuntimeOptions{})
		d.logger.Debug("sdk request 'waf.DescribeDomainDetail'", slog.Any("request", describeDomainDetailReq), slog.Any("response", describeDomainDetailResp))
		if err != nil {
			return fmt.Errorf("failed to execute sdk request 'waf.DescribeDomainDetail': %w", err)
		}

		// 修改 CNAME 接入资源
		// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-modifydomain
		modifyDomainReq := &aliwaf.ModifyDomainRequest{
			RegionId:   tea.String(d.config.Region),
			InstanceId: tea.String(d.config.InstanceId),
			Domain:     tea.String(d.config.Domain),
			Listen:     &aliwaf.ModifyDomainRequestListen{CertId: tea.String(cloudCertId)},
			Redirect:   &aliwaf.ModifyDomainRequestRedirect{Loadbalance: tea.String("iphash")},
		}
		modifyDomainReq = _assign(modifyDomainReq, describeDomainDetailResp.Body)
		modifyDomainResp, err := d.sdkClient.ModifyDomainWithContext(ctx, modifyDomainReq, &dara.RuntimeOptions{})
		d.logger.Debug("sdk request 'waf.ModifyDomain'", slog.Any("request", modifyDomainReq), slog.Any("response", modifyDomainResp))
		if err != nil {
			return fmt.Errorf("failed to execute sdk request 'waf.ModifyDomain': %w", err)
		}
	}

	return nil
}

func createSDKClient(accessKeyId, accessKeySecret, region string) (*aliwaf.Client, error) {
	// 接入点一览：https://api.aliyun.com/product/waf-openapi
	var endpoint string
	switch region {
	case "":
		endpoint = "wafopenapi.cn-hangzhou.aliyuncs.com"
	default:
		endpoint = fmt.Sprintf("wafopenapi.%s.aliyuncs.com", region)
	}

	config := &aliopen.Config{
		AccessKeyId:     tea.String(accessKeyId),
		AccessKeySecret: tea.String(accessKeySecret),
		Endpoint:        tea.String(endpoint),
	}

	client, err := aliwaf.NewClient(config)
	if err != nil {
		return nil, err
	}

	return client, nil
}

func _assign(source *aliwaf.ModifyDomainRequest, target *aliwaf.DescribeDomainDetailResponseBody) *aliwaf.ModifyDomainRequest {
	// `ModifyDomain` 中不传的字段表示使用默认值、而非保留原值，
	// 因此这里需要把原配置中的参数重新赋值回去。

	if target == nil {
		return source
	}

	if target.Listen != nil {
		if source.Listen == nil {
			source.Listen = &aliwaf.ModifyDomainRequestListen{}
		}

		if target.Listen.CipherSuite != nil {
			source.Listen.CipherSuite = tea.Int32(int32(*target.Listen.CipherSuite))
		}

		if target.Listen.CustomCiphers != nil {
			source.Listen.CustomCiphers = target.Listen.CustomCiphers
		}

		if target.Listen.EnableTLSv3 != nil {
			source.Listen.EnableTLSv3 = target.Listen.EnableTLSv3
		}

		if target.Listen.ExclusiveIp != nil {
			source.Listen.ExclusiveIp = target.Listen.ExclusiveIp
		}

		if target.Listen.FocusHttps != nil {
			source.Listen.FocusHttps = target.Listen.FocusHttps
		}

		if target.Listen.Http2Enabled != nil {
			source.Listen.Http2Enabled = target.Listen.Http2Enabled
		}

		if target.Listen.HttpPorts != nil {
			source.Listen.HttpPorts = lo.Map(target.Listen.HttpPorts, func(v *int64, _ int) *int32 {
				if v == nil {
					return nil
				}
				return tea.Int32(int32(*v))
			})
		}

		if target.Listen.HttpsPorts != nil {
			source.Listen.HttpsPorts = lo.Map(target.Listen.HttpsPorts, func(v *int64, _ int) *int32 {
				if v == nil {
					return nil
				}
				return tea.Int32(int32(*v))
			})
		}

		if target.Listen.IPv6Enabled != nil {
			source.Listen.IPv6Enabled = target.Listen.IPv6Enabled
		}

		if target.Listen.ProtectionResource != nil {
			source.Listen.ProtectionResource = target.Listen.ProtectionResource
		}

		if target.Listen.TLSVersion != nil {
			source.Listen.TLSVersion = target.Listen.TLSVersion
		}

		if target.Listen.XffHeaderMode != nil {
			source.Listen.XffHeaderMode = tea.Int32(int32(*target.Listen.XffHeaderMode))
		}

		if target.Listen.XffHeaders != nil {
			source.Listen.XffHeaders = target.Listen.XffHeaders
		}
	}

	if target.Redirect != nil {
		if source.Redirect == nil {
			source.Redirect = &aliwaf.ModifyDomainRequestRedirect{}
		}

		if target.Redirect.Backends != nil {
			source.Redirect.Backends = lo.Map(target.Redirect.Backends, func(v *aliwaf.DescribeDomainDetailResponseBodyRedirectBackends, _ int) *string {
				if v == nil {
					return nil
				}
				return v.Backend
			})
		}

		if target.Redirect.BackupBackends != nil {
			source.Redirect.BackupBackends = lo.Map(target.Redirect.BackupBackends, func(v *aliwaf.DescribeDomainDetailResponseBodyRedirectBackupBackends, _ int) *string {
				if v == nil {
					return nil
				}
				return v.Backend
			})
		}

		if target.Redirect.ConnectTimeout != nil {
			source.Redirect.ConnectTimeout = target.Redirect.ConnectTimeout
		}

		if target.Redirect.FocusHttpBackend != nil {
			source.Redirect.FocusHttpBackend = target.Redirect.FocusHttpBackend
		}

		if target.Redirect.Keepalive != nil {
			source.Redirect.Keepalive = target.Redirect.Keepalive
		}

		if target.Redirect.KeepaliveRequests != nil {
			source.Redirect.KeepaliveRequests = target.Redirect.KeepaliveRequests
		}

		if target.Redirect.KeepaliveTimeout != nil {
			source.Redirect.KeepaliveTimeout = target.Redirect.KeepaliveTimeout
		}

		if target.Redirect.Loadbalance != nil {
			source.Redirect.Loadbalance = target.Redirect.Loadbalance
		}

		if target.Redirect.ReadTimeout != nil {
			source.Redirect.ReadTimeout = target.Redirect.ReadTimeout
		}

		if target.Redirect.RequestHeaders != nil {
			source.Redirect.RequestHeaders = lo.Map(target.Redirect.RequestHeaders, func(v *aliwaf.DescribeDomainDetailResponseBodyRedirectRequestHeaders, _ int) *aliwaf.ModifyDomainRequestRedirectRequestHeaders {
				if v == nil {
					return nil
				}
				return &aliwaf.ModifyDomainRequestRedirectRequestHeaders{
					Key:   v.Key,
					Value: v.Value,
				}
			})
		}

		if target.Redirect.Retry != nil {
			source.Redirect.Retry = target.Redirect.Retry
		}

		if target.Redirect.SniEnabled != nil {
			source.Redirect.SniEnabled = target.Redirect.SniEnabled
		}

		if target.Redirect.SniHost != nil {
			source.Redirect.SniHost = target.Redirect.SniHost
		}

		if target.Redirect.WriteTimeout != nil {
			source.Redirect.WriteTimeout = target.Redirect.WriteTimeout
		}

		if target.Redirect.XffProto != nil {
			source.Redirect.XffProto = target.Redirect.XffProto
		}
	}

	return source
}
