package clusterconfig

import (
	"context"

	apiv1 "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	configcenter "github.com/tidbcloud/config-center/proto/config_center"
)

const defaultVersion = "v8.5.0"
const tiproxyVersion = "v1.3.3-alpha.1"
const dmVersion = "v8.5.0"

// workerImageRepo/Tag for tikv-worker, tidb-worker, coprocessor-worker which don't have public images.
// Uses busybox as stub - these won't function in local-dev but won't crash with ImagePullBackOff.
const workerImageRepo = "busybox"
const workerImageTag = "1.34.1"

var componentImages = map[apiv1.ComponentType]string{
	apiv1.ComponentType_PD:                 "pd",
	apiv1.ComponentType_PD_TSO:             "pd",
	apiv1.ComponentType_PD_SCHEDULING:      "pd",
	apiv1.ComponentType_TIKV:               "tikv",
	apiv1.ComponentType_TIKV_WORKER:        workerImageRepo,
	apiv1.ComponentType_TIDB:               "tidb",
	apiv1.ComponentType_TIDB_WORKER:        workerImageRepo,
	apiv1.ComponentType_TIFLASH_COMPUTE:    "tiflash",
	apiv1.ComponentType_TIFLASH_WRITE:      "tiflash",
	apiv1.ComponentType_TIPROXY:            "tiproxy",
	apiv1.ComponentType_RESOURCE_MANAGER:   "pd",
	apiv1.ComponentType_COPROCESSOR_WORKER: workerImageRepo,
}

var defaultConfigs = map[apiv1.ComponentType]string{
	apiv1.ComponentType_PD: `
[replication]
max-replicas = 3
`,
	apiv1.ComponentType_PD_TSO: `
[replication]
max-replicas = 3
`,
	apiv1.ComponentType_PD_SCHEDULING: `
[replication]
max-replicas = 3
`,
	apiv1.ComponentType_TIKV: `
[server]
grpc-concurrency = 4
`,
	apiv1.ComponentType_TIKV_WORKER: `
[server]
grpc-concurrency = 4
`,
	apiv1.ComponentType_TIDB: `
[performance]
max-procs = 0
`,
	apiv1.ComponentType_TIDB_WORKER: `
[performance]
max-procs = 0
`,
	apiv1.ComponentType_TIFLASH_COMPUTE: `
[flash]
service_addr = "0.0.0.0:3930"
`,
	apiv1.ComponentType_TIFLASH_WRITE: `
[flash]
service_addr = "0.0.0.0:3930"
`,
	apiv1.ComponentType_TIPROXY: `
[proxy]
# addr is managed by TiDB Operator v2, do not set here
`,
	apiv1.ComponentType_RESOURCE_MANAGER: `
[server]
lease = "3s"
`,
}

type MockClient struct{}

func NewMockClient() Client {
	return &MockClient{}
}

func (m *MockClient) GetDefaultVersion(ctx context.Context, tenantId string) (string, error) {
	return defaultVersion, nil
}

func (m *MockClient) GetEffectiveComponentImageTag(ctx context.Context, sharedPool *entity.SharedPool, componentType entity.ComponentType) (string, error) {
	return defaultVersion, nil
}

func (m *MockClient) CreateClusterMeta(ctx context.Context, sharedPool *entity.SharedPool, tenantId, metaProfileId string) error {
	return nil
}

func (m *MockClient) EnsurePDMicroserviceComponents(ctx context.Context, sharedPool *entity.SharedPool) error {
	return nil
}

func (m *MockClient) CreateNewComponentConfig(ctx context.Context, sharedPool *entity.SharedPool, componentGroup *entity.Component) error {
	return nil
}

func (m *MockClient) DeleteTiKVComponentConfig(ctx context.Context, sharedPool *entity.SharedPool, componentGroup *entity.Component) error {
	return nil
}

func (m *MockClient) AddBRComponentsToClusterMeta(ctx context.Context, sharedPool *entity.SharedPool, tenantId, metaProfileId string) error {
	return nil
}

func (m *MockClient) AddExportComponentsToClusterMeta(ctx context.Context, tidbCluster *entity.TiDBCluster) error {
	return nil
}

func (m *MockClient) CreateTiDBClusterMeta(ctx context.Context, sharedPool *entity.SharedPool, tidbCluster *entity.TiDBCluster) error {
	return nil
}

func (m *MockClient) CreateTiDBGroupConfig(ctx context.Context, tidbGroup *entity.TiDBGroup) error {
	return nil
}

func (m *MockClient) DeleteClusterMeta(ctx context.Context, sharedPoolId string) error {
	return nil
}

func (m *MockClient) DeleteTiDBClusterMeta(ctx context.Context, tidbClusterId string) error {
	return nil
}

func (m *MockClient) DeleteTiDBGroupConfig(ctx context.Context, tidbClusterId, tidbGroupId string) error {
	return nil
}

func (m *MockClient) GetComponentVersionAndConfig(ctx context.Context, sharedPool *entity.SharedPool, component *entity.Component) (string, *entity.ComponentConfiguration, error) {
	configContent := defaultConfigs[component.GetComponentType()]
	if configContent == "" {
		configContent = "# empty config"
	}
	imageRepo := componentImages[component.GetComponentType()]
	if imageRepo == "" {
		imageRepo = "pd"
	}

	version := defaultVersion
	switch component.GetComponentType() {
	case apiv1.ComponentType_TIPROXY:
		version = tiproxyVersion
	case apiv1.ComponentType_TIKV_WORKER, apiv1.ComponentType_TIDB_WORKER, apiv1.ComponentType_COPROCESSOR_WORKER:
		version = workerImageTag
	}

	return version, &entity.ComponentConfiguration{
		ConfigurationFileContent: configContent,
		ImageRepo:                imageRepo,
		ImageTag:                 version,
	}, nil
}

func (m *MockClient) GetDMComponentVersionAndConfig(ctx context.Context, sharedPool *entity.SharedPool) (string, *entity.ComponentConfiguration, error) {
	return dmVersion, &entity.ComponentConfiguration{
		ImageRepo: "data-migration",
		ImageTag:  dmVersion,
	}, nil
}

func (m *MockClient) GetBRComponentVersionAndConfig(ctx context.Context, sharedPool *entity.SharedPool, tenantId string, componentType entity.ComponentType) (string, *entity.ComponentConfiguration, error) {
	return defaultVersion, &entity.ComponentConfiguration{
		ConfigurationFileContent: "# BR config",
		ImageRepo:                "br",
		ImageTag:                 defaultVersion,
	}, nil
}

func (m *MockClient) GetExportComponentVersionAndConfig(ctx context.Context, tidbCluster *entity.TiDBCluster, componentType entity.ComponentType) (string, *entity.ComponentConfiguration, error) {
	return defaultVersion, &entity.ComponentConfiguration{
		ConfigurationFileContent: "# export config",
		ImageRepo:                "dumpling",
		ImageTag:                 defaultVersion,
	}, nil
}

func (m *MockClient) GetClusterInitSqlStmts(ctx context.Context, sharedPoolId string) (string, error) {
	return "", nil
}

func (m *MockClient) GetClusterTiDBSemConfig(ctx context.Context, sharedPoolId string) (string, error) {
	return "", nil
}

func (m *MockClient) GetTiDBClusterVersion(ctx context.Context, tidbGroup *entity.TiDBCluster) (string, error) {
	return defaultVersion, nil
}

func (m *MockClient) GetTiDBClusterVersionAndConfig(ctx context.Context, tidbGroup *entity.TiDBGroup, componentType entity.ComponentType) (string, *entity.ComponentConfiguration, error) {
	configContent := defaultConfigs[componentType]
	if configContent == "" {
		configContent = "# empty config"
	}
	imageRepo := componentImages[componentType]
	if imageRepo == "" {
		imageRepo = "tidb"
	}

	version := defaultVersion
	switch componentType {
	case apiv1.ComponentType_TIPROXY:
		version = tiproxyVersion
	case apiv1.ComponentType_TIKV_WORKER, apiv1.ComponentType_TIDB_WORKER, apiv1.ComponentType_COPROCESSOR_WORKER:
		version = workerImageTag
	}

	return version, &entity.ComponentConfiguration{
		ConfigurationFileContent: configContent,
		ImageRepo:                imageRepo,
		ImageTag:                 version,
	}, nil
}

func (m *MockClient) GetClient() configcenter.ConfigCenterServiceClient {
	return nil
}
