package export

import (
	"fmt"
	"strings"
	"time"

	"github.com/tidbcloud/dataflow-service-e2e/cases"
	"github.com/tidbcloud/dataflow-service-e2e/cases/essential/common"
	"github.com/tidbcloud/dataflow-service-e2e/internal/config"
	. "github.com/tidbcloud/dataflow-service-e2e/internal/model"
	"github.com/tidbcloud/dataflow-service-e2e/internal/tidbcloud/essential"
)

type ExportCancellationCase struct {
	cases.BaseCase
	provider CloudProviderType
	id       string
	req      essential.ExportRequest
}

func NewExportCancellationSmokeCase(provider CloudProviderType) cases.E2ECase {
	return &ExportCancellationCase{provider: provider}
}

func (c *ExportCancellationCase) Name() string {
	return fmt.Sprintf("%sEssentialV1ExportCancellationSmoke", c.provider)
}
func (c *ExportCancellationCase) Tags() map[string]string {
	return map[string]string{cases.TagKeyDomain: config.DomainExport, cases.TagKeyAPIModes: common.APIModesBoth}
}
func (c *ExportCancellationCase) DeclareDependencyRequirements() map[string]DependencyRequirement {
	region := config.GlobalConfig.DefaultRegionOf(c.provider)
	return map[string]DependencyRequirement{
		"essential": &TiDBServerlessRequirement{
			Dedicated: true,
			TiDBServerlessDimensions: TiDBServerlessDimensions{
				CloudProvider: c.provider,
				Region:        region,
				ServicePlan:   essential.ServicePlanEssential,
			},
		},
	}
}

func (c *ExportCancellationCase) Run() {
	cluster := c.TiDBServerless("essential")
	c.Step("seed cancellation fixture", func() error {
		_, err := common.WriteMarker(cluster, c.Name()+"-"+common.UniqueRunSuffix())
		return err
	})
	target, err := exportTarget(c.provider)
	c.Step("validate export cancellation target", func() error { return err })
	if err != nil {
		return
	}
	prefix := strings.TrimRight(target.TargetURI, "/") + "/" + strings.ToLower(c.Name()) + "-" + common.UniqueRunSuffix() + "/"
	c.req = essential.ExportRequest{OrgID: cluster.OrgID, ProjectID: cluster.ProjectID, ClusterID: cluster.ClusterID, TargetURI: prefix, Region: target.Region, Endpoint: target.Endpoint, RoleARN: target.RoleARN, AccessKeyID: target.AccessKeyID, AccessKeySecret: target.AccessKeySecret, Provider: c.provider, DisplayName: c.Name()}
	client := essential.NewExportClient(c.Logger())
	// AWS staging currently denies runner access to the target bucket. Keep
	// object cleanup enabled for AliCloud, but skip it for AWS until the IAM
	// fixture regression is fixed.
	if inspectExportTargetObjects(c.provider) {
		// Reverse registration preserves delete -> absence -> object cleanup
		// even when a cleanup assertion calls FailNow.
		defer func() {
			c.Step("delete and verify cancellation object prefix", func() error {
				return essential.DeleteObjectPrefix(c.CleanupContext(), c.req)
			})
		}()
	}
	defer func() {
		if c.id != "" {
			c.Expect("canceled export deleted", func() error {
				exists, cleanupErr := client.Exists(c.CleanupContext(), c.req, c.id)
				if cleanupErr != nil {
					return cleanupErr
				}
				if exists {
					return fmt.Errorf("export %s still exists during cleanup", c.id)
				}
				return nil
			}, 30, 15*time.Second)
		}
	}()
	defer func() {
		if c.id != "" {
			c.RetryDo("delete canceled export", func() error {
				return client.Delete(c.CleanupContext(), c.req, c.id)
			}, 3, time.Minute)
		}
	}()
	c.Step("create export for cancellation", func() error {
		c.id, err = client.Create(c.Context(), c.req)
		return err
	})
	if err != nil {
		return
	}
	c.Step("cancel export immediately", func() error { return client.Cancel(c.Context(), c.req, c.id) })
	c.Expect("export reaches canceled state", func() error {
		state, e := client.Get(c.Context(), c.req, c.id)
		if e != nil {
			return e
		}
		return validateCanceledState(state)
	}, 30, 10*time.Second)
}
