package main

import "github.com/tidbcloud/config-service/sdk/api"

const (
	metaFile                 = "meta.yaml"
	tikvConfigFile           = "tikv.toml"
	pdConfigFile             = "pd.toml"
	tidbConfigFile           = "tidb.toml"
	tiproxyConfigFile        = "tiproxy.toml"
	tiflashConfigFile        = "tiflash.toml"
	tiflashLearnerConfigFile = "tiflash-learner.toml"
	backupConfigFile         = "backup.yaml"
	restoreConfigFile        = "restore.yaml"
	lightningConfigFile      = "lightning.toml"
	ticdcConfigFile          = "ticdc.toml"

	baseDir      = "base"
	versionsDir  = "versions"
	instancesDir = "instances"
	tenantsDir   = "tenants"
	clustersDir  = "clusters"

	tidbConfigurationRepo = "https://github.com/tidbcloud/tidb-configuration"
)

type Component string

const (
	ComponentTiDB           Component = "tidb"
	ComponentPD             Component = "pd"
	ComponentTiProxy        Component = "tiproxy"
	ComponentTiKV           Component = "tikv"
	ComponentTiFlash        Component = "tiflash"
	ComponentTiFlashLearner Component = "tiflash-learner"
	ComponentBackup         Component = "backup"
	ComponentRestore        Component = "restore"
	ComponentLightning      Component = "lightning"
	ComponentTiCDC          Component = "ticdc"
)

var componentToFile map[Component]string

func init() {
	componentToFile = map[Component]string{
		ComponentTiDB:           tidbConfigFile,
		ComponentPD:             pdConfigFile,
		ComponentTiKV:           tikvConfigFile,
		ComponentTiProxy:        tiproxyConfigFile,
		ComponentTiFlash:        tiflashConfigFile,
		ComponentTiFlashLearner: tiflashLearnerConfigFile,
		ComponentBackup:         backupConfigFile,
		ComponentRestore:        restoreConfigFile,
		ComponentLightning:      lightningConfigFile,
		ComponentTiCDC:          ticdcConfigFile,
	}
}

// Tree is the programmatic view of the layered config directory
type Tree struct {
	// global default meta, required
	GlobalMeta *Meta
	// must include all supported versions, required
	VersionedConfigs []VersionedConfig
	// tenant's overlays, optional
	TenantOverlays []TenantOverlay
}

type VersionedConfig struct {
	// overrides the metas for this specific version, optional
	Meta *Meta
	// base configs for this version, required
	Configs ComponentConfigs
	// instance type overlays, e.g. aws.i3.2xlarge, optional
	InstanceOverlays []InstanceOverlay
}

type InstanceOverlay struct {
	InstanceType string

	Configs ComponentConfigs
}

type TenantOverlay struct {
	// do not assume the type of tenantID, simply use string literal
	TenantID string

	// tenant's default meta, optional
	Meta *Meta

	Configs ComponentConfigs

	// further specify overlay for specific clusters of this tenant, optional
	ClusterOverlays []ClusterOverlay
}

type ClusterOverlay struct {
	// do not assume the type of tenantID, simply use string literal
	ClusterID string

	// override cluster's meta, optional
	Meta *Meta

	Configs ComponentConfigs
}

type Meta struct {
	Version          string  `yaml:"version"`
	Images           *Images `yaml:"images,omitempty"`
	UpdatePolicy     string  `yaml:"updatePolicy,omitempty"`
	EnableGOMEMLIMIT bool    `yaml:"enableGOMEMLIMIT"`
}

type Images struct {
	TiDB      *Image `yaml:"tidb,omitempty"`
	TiKV      *Image `yaml:"tikv,omitempty"`
	PD        *Image `yaml:"pd,omitempty"`
	TiFlash   *Image `yaml:"tiflash,omitempty"`
	TiProxy   *Image `yaml:"tiproxy,omitempty"`
	Backup    *Image `yaml:"backup,omitempty"`
	Restore   *Image `yaml:"restore,omitempty"`
	Lightning *Image `yaml:"lightning,omitempty"`
	TiCDC     *Image `yaml:"ticdc,omitempty"`
}

type Image struct {
	BaseImage *string `yaml:"baseImage"`
	Tag       *string `yaml:"tag"`
}

type ComponentConfig struct {
	Component Component
	Config    *api.TomlConfig
}

type ComponentConfigs []ComponentConfig

func (cs ComponentConfigs) GetConfig(component Component) *api.TomlConfig {
	for _, c := range cs {
		if c.Component == component {
			return c.Config
		}
	}
	return nil
}

func (cs ComponentConfigs) Get(component Component) *ComponentConfig {
	for _, c := range cs {
		if c.Component == component {
			return &c
		}
	}
	return nil
}
