package common

import (
	"fmt"
	"net"
	"strings"
	"time"

	"github.com/avast/retry-go/v4"
	"github.com/tidbcloud/dataflow-service-e2e/cases"
	. "github.com/tidbcloud/dataflow-service-e2e/internal/model"
	"github.com/tidbcloud/dataflow-service-e2e/internal/tidbcloud/essential"
)

func RequireMySQLPrivateLinkFixture(name string, fixture *MySQLEntity) error {
	if fixture == nil {
		return fmt.Errorf("%s requires a MySQL PrivateLink fixture", name)
	}
	if strings.TrimSpace(fixture.PrivateLinkServiceName) == "" {
		return fmt.Errorf("%s requires a configured PrivateLink service name", name)
	}
	// Endpoint is consumed only by the E2E runner when it seeds or verifies the
	// external MySQL fixture. Essential product requests use Ports[0] together
	// with the runtime PrivateLink connection ID and never send this endpoint.
	if strings.TrimSpace(fixture.Endpoint) == "" {
		return fmt.Errorf("%s requires a runner-reachable MySQL management endpoint for seed and validation", name)
	}
	if _, _, err := net.SplitHostPort(fixture.Endpoint); err != nil {
		return fmt.Errorf("%s MySQL management endpoint must be host:port: %w", name, err)
	}
	if len(fixture.Ports) == 0 || fixture.Ports[0] <= 0 || fixture.Ports[0] > 65535 {
		return fmt.Errorf("%s requires a valid MySQL PrivateLink product port", name)
	}
	return nil
}
func WaitPrivateLinkActive(c *cases.BaseCase, client essential.PrivateLinkClient, cluster *TiDBServerlessEntity, id string) {
	c.Expect("PrivateLink connection active", func() error {
		detail, err := client.Get(c.Context(), cluster, id)
		if err != nil {
			return err
		}
		switch detail.State {
		case essential.PrivateLinkActive:
			return nil
		case essential.PrivateLinkFailed:
			return retry.Unrecoverable(fmt.Errorf("PrivateLink connection failed: %s", detail.Message))
		case essential.PrivateLinkPendingAcceptance:
			return fmt.Errorf("PrivateLink connection pending acceptance")
		default:
			return fmt.Errorf("PrivateLink connection state is %s", detail.State)
		}
	}, 80, 15*time.Second)
}

func CleanupPrivateLink(c *cases.BaseCase, client essential.PrivateLinkClient, cluster *TiDBServerlessEntity, id string) {
	if id == "" {
		return
	}
	detail, err := client.Get(c.CleanupContext(), cluster, id)
	if err != nil && essential.IsEssentialResourceNotFound(err) {
		return
	}
	c.Step("inspect PrivateLink connection for cleanup", func() error { return err })
	if detail != nil {
		for _, domainID := range detail.AttachedDomain {
			domainID := domainID
			c.Step("detach PrivateLink domain", func() error {
				return client.DetachDomains(c.CleanupContext(), cluster, id, domainID)
			})
		}
	}
	c.RetryDo("delete PrivateLink connection", func() error { return client.Delete(c.CleanupContext(), cluster, id) }, 3, time.Minute)
	c.Expect("PrivateLink connection deleted", func() error {
		exists, err := client.Exists(c.CleanupContext(), cluster, id)
		if err != nil {
			return err
		}
		if exists {
			return fmt.Errorf("PrivateLink connection %s still exists", id)
		}
		return nil
	}, 40, 15*time.Second)
}
