package clustergateway

import (
	"context"
	"errors"
	"fmt"

	"github.com/pingcap/kvproto/pkg/keyspacepb"
	"github.com/pingcap/kvproto/pkg/metapb"
	clusteragentv1 "github.com/tidbcloud/cluster-service-ng/api/tidbcloud/cluster-agent/v1"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	pdapiv2 "github.com/tikv/pd/server/apiv2/handlers"
)

var ErrFlushWALUnsupported = errors.New("FlushWAL is unsupported")

type FlushWALHTTPError struct {
	StatusCode int
}

func (e *FlushWALHTTPError) Error() string {
	return fmt.Sprintf("FlushWAL returned HTTP status %d", e.StatusCode)
}

type Client interface {
	// PD API
	UpdateKeySpaceState(ctx context.Context, sharedPool *entity.SharedPool, keySpace string, state keyspacepb.KeyspaceState) error
	CreateKeySpace(ctx context.Context, sharedPool *entity.SharedPool, keySpace, cmekId string, encryptionContext map[string]string) error
	GetKeySpace(ctx context.Context, sharedPool *entity.SharedPool, keySpace string) (*pdapiv2.KeyspaceMeta, error)
	ListKeySpaces(ctx context.Context, sharedPool *entity.SharedPool) (*pdapiv2.LoadAllKeyspacesResponse, error)
	GetCluster(ctx context.Context, sharedPool *entity.SharedPool) (*metapb.Cluster, error)

	// DM API
	ListActiveDMSourceCount(ctx context.Context, sharedPool *entity.SharedPool, dmClusterID string) (int, error)

	// Resource Group API
	SetKeySpaceResourceGroup(ctx context.Context, sharedPool *entity.SharedPool, keySpace string, req *RCURequest) error
	// SetKeySpaceRuVersion sets the RU version for a keyspace via the controller config API.
	// Returns ErrRuVersionNotSupported when PD does not support the API (HTTP 404).
	SetKeySpaceRuVersion(ctx context.Context, sharedPool *entity.SharedPool, keySpace string, req *SetKeyspaceRuVersionRequest) error

	// BR API
	// Notice: there is no documentation or well format definition for BR API in kernel side, if you want make changes to this logic, please refer to the kernel code directly
	// code reference: https://github.com/tidbcloud/cloud-storage-engine/blob/b7346f6a33479389bff95ecfe4c9dfefa085c25a/components/cloud_worker/src/native_br.rs#L47-L59
	GetLightweightBackup(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string, request *GetLightweightBackupRequest) (*KernelLightweightBackupItem, error)
	ListLightweightBackups(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string, request *ListLightweightBackupsRequest) (*ListLightweightBackupsResponse, error)
	CreateLightweightBackup(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string) (*CreateLightweightBackupResponse, error)
	CreateLightweightRestore(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string, request *CreateLightweightRestoreRequest) (*KernelLightweightRestore, error)
	GetLightweightRestore(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string, request *KernelLightweightRestoreIdentity) (*KernelLightweightRestore, error)
	DeleteLightweightRestore(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string, request *KernelLightweightRestoreIdentity) error
	CreatePackBackupTask(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string, request *CreatePackBackupTaskRequest) (*TaskResponse, error)
	CreateCopyPackedBackupTask(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string, request *CreateCopyPackedBackupTaskRequest) (*TaskResponse, error)
	CreateRestorePackedBackupTask(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string, request *CreateRestorePackedBackupTaskRequest) (*TaskResponse, error)
	GetTiBRTask(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string, taskId string) (*TaskResponse, error)
	DeleteTiBRTask(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string, taskId string) (*TaskResponse, error)
	GetExoticBackupInfo(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName, exoticBackup string) (*ExoticBackupInfo, error)
	GetBackupStatus(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string) (*BackupStatus, error)
	FlushWAL(ctx context.Context, sharedPool *entity.SharedPool, tibrCRName string) error

	// Cluster Agent Ops API
	ClusterAgentOpsRestart(ctx context.Context, sharedPool *entity.SharedPool, request *clusteragentv1.RestartReq) error
	GetClusterTopology(ctx context.Context, sharedPool *entity.SharedPool, request *clusteragentv1.GetClusterTopologyReq) (*clusteragentv1.GetClusterTopologyResp, error)
	DeleteCloudAdmin(ctx context.Context, sharedPool *entity.SharedPool, request *clusteragentv1.DeleteCloudAdminReq) (*clusteragentv1.DeleteCloudAdminResp, error)
	ListPods(ctx context.Context, sharedPool *entity.SharedPool) (*clusteragentv1.ListPodsResp, error)
	GetComponentResourceMetrics(ctx context.Context, sharedPool *entity.SharedPool, componentType, componentId string) (*clusteragentv1.GetComponentResourceMetricsResp, error)
	// GetComponentRawMetrics proxies raw Prometheus metrics from a specific component pod's /metrics endpoint.
	// Returns the raw Prometheus text body as bytes. Only "tikv" is currently supported on the cluster-agent side.
	GetComponentRawMetrics(ctx context.Context, sharedPool *entity.SharedPool, componentType, podName string) ([]byte, error)
	// GetComponentNodeMetrics proxies raw Prometheus metrics from the node-exporter instance
	// co-located with the given component pod.
	// Returns the raw Prometheus text body as bytes. Only "tikv" is currently supported.
	GetComponentNodeMetrics(ctx context.Context, sharedPool *entity.SharedPool, componentType, podName string) ([]byte, error)
	MarkTiProxyPodUnhealthyLegacy(ctx context.Context, sharedPool *entity.SharedPool, request *clusteragentv1.MarkTiProxyPodUnhealthyLegacyReq) error
	ProbeTiProxyHealthAPI(ctx context.Context, sharedPool *entity.SharedPool, request *clusteragentv1.ProbeTiProxyHealthAPIReq) (*clusteragentv1.ProbeTiProxyHealthAPIResp, error)
	ListPlanReplayerFiles(ctx context.Context, sharedPool *entity.SharedPool, request *clusteragentv1.ListPlanReplayerFilesReq) (*clusteragentv1.ListPlanReplayerFilesResp, error)
	GeneratePlanReplayerFileDownloadURL(ctx context.Context, sharedPool *entity.SharedPool, request *clusteragentv1.GeneratePlanReplayerFileDownloadURLReq) (*clusteragentv1.GeneratePlanReplayerFileDownloadURLResp, error)
}

// RCURequest is copied KeyspaceServiceLimitRequest from https://github.com/tikv/pd/pull/9354/files#diff-eeee097da5c4880e609179fc6e178079c9fbf06f4415da7f0370c616fa22f60e
type RCURequest struct {
	ServiceLimit float64 `json:"service_limit"`
}

// SetKeyspaceRuVersionRequest is the request body for setting the RU version of a keyspace
// via the /config/controller/ru_version/{keyspace_name} endpoint (tikv/pd#10334).
type SetKeyspaceRuVersionRequest struct {
	RuVersion int32 `json:"ru_version"`
}
