package provider

import (
	"context"
	"time"

	"github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
	"github.com/tidbcloud/config-service/sdk/api"
	storagev1 "k8s.io/api/storage/v1"
	"k8s.io/apimachinery/pkg/labels"
	"sigs.k8s.io/controller-runtime/pkg/client"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/nodegroup"
)

type Provider interface {
	Cluster
}

type Cluster interface {
	GetComponentNodeLabels(componentType cloudv1.ComponentType) map[string]string
	GetComponentPodLabels(componentType cloudv1.ComponentType) map[string]string
}

type Machine interface {
	FindInstanceType(name string) (cloudv1.InstanceType, error)
}

type ClusterReader interface {
	GetClient(context.Context, *cloudv1.Cluster) (client.Client, error)
	GetKubernetesStatus(*cloudv1.Cluster) (*cloudv1.KubernetesStatus, error)
}

type GitOps interface {
	GetClusterConfig(context.Context, *cloudv1.Cluster) (*api.DescribeClusterConfigOutput, error)
}

type BRNodeGroup interface {
	CreateBRNode(
		ctx context.Context,
		network *cloudv1.Network,
		ngSpec *cloudv1.NodegroupSpec) error
	DeleteBRNode(
		ctx context.Context,
		network *cloudv1.Network,
		ngSpecName string) error
}

type Backup interface {
	BRNodeGroup
	ClusterReader

	BuildBackup(*cloudv1.Backup, *cloudv1.Cluster) (*v1alpha1.Backup, error)
	GetBackupClient(context.Context, *cloudv1.Backup) (client.Client, error)
	GetBackupNamespace(context.Context, *cloudv1.Backup) (string, error)
}

type Restore interface {
	BRNodeGroup
	ClusterReader

	BuildRestore(*cloudv1.Restore, *cloudv1.Cluster) (*v1alpha1.Restore, error)
	IsDPCompatMode() bool
}

type Cdc interface {
	// GetUpstreamClient get k8s client in upstream, will only used for cross region.
	GetCdcUpstreamClient(context.Context, *cloudv1.TiCDC) (client.Client, error)
	// GetClient get k8s client in current network.
	// If cdc used for kafka/mysql, cdc and tidb will deploy in same k8s cluster
	// If cdc used for cross region, cdc will deploy to downstream
	GetCdcClient(context.Context, *cloudv1.Network) (client.Client, error)
	// GetKubernetesStatus get k8s status of cdc.
	GetCdcKubernetesStatus(*cloudv1.Cluster) (*cloudv1.KubernetesStatus, error)
	// CreateCdcNodeGroup create cdc nodegroup. eks provider will create nodegroup in eks cluster. aws/gcp provider will do nothing.
	// aws/gcp provider manage cdc nodes by node controller
	CreateCdcNodeGroup(context.Context, *cloudv1.TiCDC, *cloudv1.Cluster, *nodegroup.Set) (map[string]string, error)
	// DeleteCdcNodeGroup delete cdc nodegroup. eks provider will delete nodegroup in eks cluster. aws/gcp provider will do nothing.
	// aws/gcp provider manage cdc nodes by node controller
	DeleteCdcNodeGroup(context.Context, *cloudv1.TiCDC, *nodegroup.Set) error
	// ReleaseNodes release node by label set
	ReleaseNodes(ctx context.Context, cr *cloudv1.TiCDC, ngNamePrefix string, labelSet labels.Set) error
	// UpdateNodegroupTopology update az nodegroups by zone topology, topology map[zone]nodeNum
	UpdateNodegroupTopology(ctx context.Context, cr *cloudv1.TiCDC, topology map[string]int) error
	// EnsureAllNodegroupsReady ensure all nodegroup of this ticdc cluster ready
	EnsureAllNodegroupsReady(ctx context.Context, cr *cloudv1.TiCDC) error
	// GetNodegroupsByFilter get node list name array by filter
	GetNodegroupsByFilter(ctx context.Context, cr *cloudv1.TiCDC, selector labels.Selector) (map[string]int, error)
	// DeleteNodegroupsByFilter delete nodegroup by filter
	DeleteNodegroupsByFilter(ctx context.Context, cr *cloudv1.TiCDC, selector labels.Selector) error
	// RequireV1CertManager return true if cdc need cert-manager v1.
	RequireV1CertManager() bool
	// CertificateOptions return certificate options for cdc.
	CertificateOptions(cluster *cloudv1.Cluster) (kind string, name string, group string, d time.Duration)
	// OverrideImage override provider image.
	OverrideImage(cluster *cloudv1.Cluster, imageName string) string
	// GetNetworkProxyBaseURL return the network proxy base url
	GetNetworkProxyBaseURL(_ context.Context, network *cloudv1.Network) (string, error)
	// Credentials gets the credential file content for cdc.
	// deprecated
	Credentials(ctx context.Context, network *cloudv1.Network) ([]byte, error)
	IsDPCompatMode() bool
	BuildStorageClass() *storagev1.StorageClass
	// SetResourceLabels set labels to compute and storage resources of cloud provider, now it is only used on gcp
	SetResourceLabels(ctx context.Context, cr *cloudv1.TiCDC) error
}
