// Copyright 2019 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package defaulting

import (
	"github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/utils/pointer"
)

const (
	defaultTiDBImage    = "pingcap/tidb"
	defaultTiKVImage    = "pingcap/tikv"
	defaultPDImage      = "pingcap/pd"
	defaultBinlogImage  = "pingcap/tidb-binlog"
	defaultTiFlashImage = "pingcap/tiflash"
	defaultTiCDCImage   = "pingcap/ticdc"
	defaultTiProxyImage = "pingcap/tiproxy"

	defaultCanaryUpgradeCoordinationSeconds = 180
	defaultCanaryUpgradeClusterReadySeconds = 600

	defaultCanaryUpgradeStageReadySeconds = 300
	defaultScaleInReplicas                = 1
	defaultScaleOutReplicas               = 1
	defaultScaleInIntervalSeconds         = 500
	defaultScaleOutIntervalSeconds        = 300
	defaultPVReclaimDelayDuration         = "168h"

	defaultScaleInProtectionStorageThreshold = 0.8
	defaultScaleInProtectionMinReplicas      = 1

	defaultStoreLimitRate          = 15
	defaultStoreUnbalanceThreshold = 0.7

	defaultMaxHotRegionsCount = 1024

	defaultHotClusterInitialReplicas = 1

	defaultCPUThreshold       = 0.5
	defaultHotDurationSeconds = 300

	defaultUpgradeDelayAfterEvictLeader  = "10m"
	defaultEndEvictLeaderDelayAfterReady = "10m"
)

var (
	tidbLogMaxBackups = 3
)

func SetTidbClusterDefault(tc *v1alpha1.TidbCluster) {
	setTidbClusterSpecDefault(tc)
	if tc.Spec.PD != nil {
		setPdSpecDefault(tc)
	}
	if tc.Spec.TiKV != nil {
		setTikvSpecDefault(tc)
	}
	if tc.Spec.TiDB != nil {
		setTidbSpecDefault(tc)
	}
	if tc.Spec.Pump != nil {
		setPumpSpecDefault(tc)
	}
	if tc.Spec.TiFlash != nil {
		setTiFlashSpecDefault(tc)
	}
	if tc.Spec.TiCDC != nil {
		setTiCDCSpecDefault(tc)
	}
	if tc.Spec.TiProxy != nil {
		setTiProxySpecDefault(tc)
	}
}

// setTidbClusterSpecDefault is only managed the property under Spec
func setTidbClusterSpecDefault(tc *v1alpha1.TidbCluster) {
	if string(tc.Spec.ImagePullPolicy) == "" {
		tc.Spec.ImagePullPolicy = corev1.PullIfNotPresent
	}
	if tc.Spec.TLSCluster == nil {
		tc.Spec.TLSCluster = &v1alpha1.TLSCluster{Enabled: false}
	}
	if tc.Spec.EnablePVReclaim == nil {
		d := false
		tc.Spec.EnablePVReclaim = &d
	}
	retainPVP := corev1.PersistentVolumeReclaimRetain
	if tc.Spec.PVReclaimPolicy == nil {
		tc.Spec.PVReclaimPolicy = &retainPVP
	}

	if tc.Spec.Cluster != nil {
		if tc.Spec.Cluster.Name != "" && tc.Spec.Cluster.Namespace == "" {
			tc.Spec.Cluster.Namespace = tc.GetNamespace()
		}
	}
	if tc.Spec.Blacklist == nil {
		tc.Spec.Blacklist = &v1alpha1.Blacklist{}
	}
	if tc.Spec.Blacklist.EnableRollingUpdate == nil {
		tc.Spec.Blacklist.EnableRollingUpdate = pointer.BoolPtr(false)
	}
	if tc.Spec.PVReclaimDelayDuration == nil {
		tc.Spec.PVReclaimDelayDuration = pointer.StringPtr(defaultPVReclaimDelayDuration)
	}
}

func setTidbSpecDefault(tc *v1alpha1.TidbCluster) {
	if len(tc.Spec.Version) > 0 || tc.Spec.TiDB.Version != nil {
		if tc.Spec.TiDB.BaseImage == "" {
			tc.Spec.TiDB.BaseImage = defaultTiDBImage
		}
	}
	if tc.Spec.TiDB.MaxFailoverCount == nil {
		tc.Spec.TiDB.MaxFailoverCount = pointer.Int32Ptr(3)
	}

	// Start set config if need.
	if tc.Spec.TiDB.Config == nil {
		return
	}
	// we only set default log
	backupKey := "log.file.max-backups"
	if v := tc.Spec.TiDB.Config.Get(backupKey); v == nil {
		tc.Spec.TiDB.Config.Set(backupKey, tidbLogMaxBackups)
	}
}

func setTikvSpecDefault(tc *v1alpha1.TidbCluster) {
	if len(tc.Spec.Version) > 0 || tc.Spec.TiKV.Version != nil {
		if tc.Spec.TiKV.BaseImage == "" {
			tc.Spec.TiKV.BaseImage = defaultTiKVImage
		}
	}
	if tc.Spec.TiKV.MaxFailoverCount == nil {
		tc.Spec.TiKV.MaxFailoverCount = pointer.Int32Ptr(3)
	}
	if tc.Spec.TiKV.Failover != nil {
		if tc.Spec.TiKV.Failover.ReplicasPerFailureStore == nil {
			tc.Spec.TiKV.Failover.ReplicasPerFailureStore = pointer.Int32Ptr(1)
		}
	}
	if tc.Spec.TiKV.EnablePVReclaim == nil {
		d := *tc.Spec.EnablePVReclaim
		tc.Spec.TiKV.EnablePVReclaim = &d
	}
	if tc.Spec.TiKV.PVReclaimDelayDuration == nil {
		tc.Spec.TiKV.PVReclaimDelayDuration = pointer.StringPtr(defaultPVReclaimDelayDuration)
	}
	if tc.Spec.TiKV.EnableConfigRollback == nil {
		tc.Spec.TiKV.EnableConfigRollback = pointer.BoolPtr(false)
	}
	if tc.Spec.TiKV.UpgradeDelayAfterEvictLeader == nil {
		tc.Spec.TiKV.UpgradeDelayAfterEvictLeader = pointer.StringPtr(defaultUpgradeDelayAfterEvictLeader)
	}
	if tc.Spec.TiKV.EndEvictLeaderDelayAfterReady == nil {
		tc.Spec.TiKV.EndEvictLeaderDelayAfterReady = pointer.StringPtr(defaultEndEvictLeaderDelayAfterReady)
	}
	if tc.Spec.TiKV.CanaryUpgrade != nil && pointer.BoolPtrDerefOr(tc.Spec.TiKV.CanaryUpgrade.Enabled, false) {
		if tc.Spec.TiKV.CanaryUpgrade.CoordinationSeconds == nil {
			tc.Spec.TiKV.CanaryUpgrade.CoordinationSeconds = pointer.Int32Ptr(defaultCanaryUpgradeCoordinationSeconds)
		}
		if tc.Spec.TiKV.CanaryUpgrade.ClusterReadySeconds == nil {
			tc.Spec.TiKV.CanaryUpgrade.ClusterReadySeconds = pointer.Int32Ptr(defaultCanaryUpgradeClusterReadySeconds)
		}
		if tc.Spec.TiKV.CanaryUpgrade.StageReadySeconds == nil {
			tc.Spec.TiKV.CanaryUpgrade.StageReadySeconds = pointer.Int32Ptr(defaultCanaryUpgradeStageReadySeconds)
		}
	}
	if tc.Spec.TiKV.AutoScaling != nil && pointer.BoolPtrDerefOr(tc.Spec.TiKV.AutoScaling.Enabled, false) {
		if tc.Spec.TiKV.AutoScaling.AllowScaleInCancel == nil {
			tc.Spec.TiKV.AutoScaling.AllowScaleInCancel = pointer.BoolPtr(true)
		}
		if tc.Spec.TiKV.AutoScaling.CPU != nil {
			if tc.Spec.TiKV.AutoScaling.CPU.ScaleInReplicas == nil {
				tc.Spec.TiKV.AutoScaling.CPU.ScaleInReplicas = pointer.Int32Ptr(defaultScaleInReplicas)
			}
			if tc.Spec.TiKV.AutoScaling.CPU.ScaleOutReplicas == nil {
				tc.Spec.TiKV.AutoScaling.CPU.ScaleOutReplicas = pointer.Int32Ptr(defaultScaleOutReplicas)
			}
			if tc.Spec.TiKV.AutoScaling.CPU.ScaleInIntervalSeconds == nil {
				tc.Spec.TiKV.AutoScaling.CPU.ScaleInIntervalSeconds = pointer.Int32Ptr(defaultScaleInIntervalSeconds)
			}
			if tc.Spec.TiKV.AutoScaling.CPU.ScaleOutIntervalSeconds == nil {
				tc.Spec.TiKV.AutoScaling.CPU.ScaleOutIntervalSeconds = pointer.Int32Ptr(defaultScaleOutIntervalSeconds)
			}
		}
		if tc.Spec.TiKV.AutoScaling.Storage != nil {
			if tc.Spec.TiKV.AutoScaling.Storage.ScaleInReplicas == nil {
				tc.Spec.TiKV.AutoScaling.Storage.ScaleInReplicas = pointer.Int32Ptr(defaultScaleInReplicas)
			}
			if tc.Spec.TiKV.AutoScaling.Storage.ScaleOutReplicas == nil {
				tc.Spec.TiKV.AutoScaling.Storage.ScaleOutReplicas = pointer.Int32Ptr(defaultScaleOutReplicas)
			}
			if tc.Spec.TiKV.AutoScaling.Storage.ScaleInIntervalSeconds == nil {
				tc.Spec.TiKV.AutoScaling.Storage.ScaleInIntervalSeconds = pointer.Int32Ptr(defaultScaleInIntervalSeconds)
			}
			if tc.Spec.TiKV.AutoScaling.Storage.ScaleOutIntervalSeconds == nil {
				tc.Spec.TiKV.AutoScaling.Storage.ScaleOutIntervalSeconds = pointer.Int32Ptr(defaultScaleOutIntervalSeconds)
			}
		}
	}
	if tc.Spec.TiKV.ScaleInProtection != nil && pointer.BoolPtrDerefOr(tc.Spec.TiKV.ScaleInProtection.Enabled, false) {
		if tc.Spec.TiKV.ScaleInProtection.StorageThreshold == nil {
			tc.Spec.TiKV.ScaleInProtection.StorageThreshold = pointer.Float64Ptr(defaultScaleInProtectionStorageThreshold)
		}
		if tc.Spec.TiKV.ScaleInProtection.MinReplicas == nil {
			tc.Spec.TiKV.ScaleInProtection.MinReplicas = pointer.Int32Ptr(defaultScaleInProtectionMinReplicas)
		}
	}
	if tc.Spec.TiKV.StoreLimit != nil && pointer.BoolPtrDerefOr(tc.Spec.TiKV.StoreLimit.Enabled, false) {
		if tc.Spec.TiKV.StoreLimit.UnbalanceThreshold == nil {
			tc.Spec.TiKV.StoreLimit.UnbalanceThreshold = pointer.Float64Ptr(defaultStoreUnbalanceThreshold)
		}
		if tc.Spec.TiKV.StoreLimit.NormalRate == nil {
			tc.Spec.TiKV.StoreLimit.NormalRate = pointer.Float64Ptr(defaultStoreLimitRate)
		}
		if tc.Spec.TiKV.StoreLimit.ScalingOutRate == nil {
			tc.Spec.TiKV.StoreLimit.ScalingOutRate = pointer.Float64Ptr(defaultStoreLimitRate)
		}
		if tc.Spec.TiKV.StoreLimit.ScalingInRate == nil {
			tc.Spec.TiKV.StoreLimit.ScalingInRate = pointer.Float64Ptr(defaultStoreLimitRate)
		}
	}
	if tc.Spec.TiKV.GroupName == nil {
		tc.Spec.TiKV.GroupName = pointer.StringPtr("")
	}
	if tc.Spec.TiKV.EnableUpgradeInNonReadyStates == nil {
		tc.Spec.TiKV.EnableUpgradeInNonReadyStates = pointer.BoolPtr(false)
	}
	if tc.Spec.TiKV.SupersedingCluster != nil {
		if tc.Spec.TiKV.SupersedingCluster.Name != "" && tc.Spec.TiKV.SupersedingCluster.Namespace == "" {
			tc.Spec.TiKV.SupersedingCluster.Namespace = tc.GetNamespace()
		}
	}
	if tc.Spec.TiKV.HotCluster != nil && tc.Spec.TiKV.HotCluster.Cluster != nil && tc.Spec.TiKV.HotCluster.Cluster.Name != "" {
		if tc.Spec.TiKV.HotCluster.Cluster.Namespace == "" {
			tc.Spec.TiKV.HotCluster.Cluster.Namespace = tc.GetNamespace()
		}
		if tc.Spec.TiKV.HotCluster.Cluster.Name == tc.GetName() && tc.Spec.TiKV.HotCluster.Cluster.Namespace == tc.GetNamespace() {
			tc.Spec.TiKV.HotCluster.CPUThreshold = nil
			tc.Spec.TiKV.HotCluster.HotDurationSeconds = nil
			if tc.Spec.TiKV.HotCluster.ScaleToZero == nil {
				tc.Spec.TiKV.HotCluster.ScaleToZero = pointer.BoolPtr(true)
			}
			if tc.Spec.TiKV.HotCluster.InitialReplicas == nil {
				tc.Spec.TiKV.HotCluster.InitialReplicas = pointer.Int32Ptr(defaultHotClusterInitialReplicas)
			}
			if tc.Spec.TiKV.HotCluster.MaxHotRegionsCount == nil {
				tc.Spec.TiKV.HotCluster.MaxHotRegionsCount = pointer.Int64Ptr(defaultMaxHotRegionsCount)
			}
			if tc.Spec.TiKV.HotCluster.HotRegionSeconds == nil {
				tc.Spec.TiKV.HotCluster.HotRegionSeconds = pointer.Int32Ptr(180)
			}
			if tc.Spec.TiKV.HotCluster.ColdRegionSeconds == nil {
				tc.Spec.TiKV.HotCluster.ColdRegionSeconds = pointer.Int32Ptr(480)
			}
			if tc.Spec.TiKV.HotCluster.RegionHeartbeatSeconds == nil {
				tc.Spec.TiKV.HotCluster.RegionHeartbeatSeconds = pointer.Int32Ptr(60)
			}
			if tc.Spec.TiKV.HotCluster.StoreHeartbeatSeconds == nil {
				tc.Spec.TiKV.HotCluster.StoreHeartbeatSeconds = pointer.Int32Ptr(10)
			}
		} else {
			if tc.Spec.TiKV.HotCluster.CPUThreshold == nil {
				tc.Spec.TiKV.HotCluster.CPUThreshold = pointer.Float64Ptr(defaultCPUThreshold)
			}
			if tc.Spec.TiKV.HotCluster.HotDurationSeconds == nil {
				tc.Spec.TiKV.HotCluster.HotDurationSeconds = pointer.Int32Ptr(defaultHotDurationSeconds)
			}
		}
	}
	if tc.Spec.TiKV.IsolatedCluster != nil && tc.Spec.TiKV.IsolatedCluster.Tier != "" {
		if tc.Spec.TiKV.IsolatedCluster.ZoneRedundant == nil {
			tc.Spec.TiKV.IsolatedCluster.ZoneRedundant = pointer.BoolPtr(false)
		}
		if tc.Spec.TiKV.IsolatedCluster.OnlyLeader == nil {
			tc.Spec.TiKV.IsolatedCluster.OnlyLeader = pointer.BoolPtr(false)
		}
	}
	if tc.Spec.TiKV.FallbackCluster != nil && tc.Spec.TiKV.FallbackCluster.Cluster != nil && tc.Spec.TiKV.FallbackCluster.Cluster.Name != "" {
		if tc.Spec.TiKV.FallbackCluster.Cluster.Namespace == "" {
			tc.Spec.TiKV.FallbackCluster.Cluster.Namespace = tc.GetNamespace()
		}
		if tc.Spec.TiKV.FallbackCluster.Cluster.Name == tc.GetName() && tc.Spec.TiKV.FallbackCluster.Cluster.Namespace == tc.GetNamespace() {
			tc.Spec.TiKV.FallbackCluster.ScaleOutTimeout = nil
		} else {
			if tc.Spec.TiKV.FallbackCluster.ScaleOutTimeout == nil {
				tc.Spec.TiKV.FallbackCluster.ScaleOutTimeout = pointer.StringPtr("10m")
			}
			if tc.Spec.TiKV.FallbackCluster.ReadyDuration == nil {
				tc.Spec.TiKV.FallbackCluster.ReadyDuration = pointer.StringPtr("10m")
			}
		}
	}
}

func setPdSpecDefault(tc *v1alpha1.TidbCluster) {
	if len(tc.Spec.Version) > 0 || tc.Spec.PD.Version != nil {
		if tc.Spec.PD.BaseImage == "" {
			tc.Spec.PD.BaseImage = defaultPDImage
		}
	}
	if tc.Spec.PD.MaxFailoverCount == nil {
		tc.Spec.PD.MaxFailoverCount = pointer.Int32Ptr(3)
	}
	if tc.Spec.PD.EnableConfigRollback == nil {
		tc.Spec.PD.EnableConfigRollback = pointer.BoolPtr(false)
	}
	if tc.Spec.PD.CanaryUpgrade != nil && pointer.BoolPtrDerefOr(tc.Spec.PD.CanaryUpgrade.Enabled, false) {
		if tc.Spec.PD.CanaryUpgrade.CoordinationSeconds == nil {
			tc.Spec.PD.CanaryUpgrade.CoordinationSeconds = pointer.Int32Ptr(defaultCanaryUpgradeCoordinationSeconds)
		}
		if tc.Spec.PD.CanaryUpgrade.ClusterReadySeconds == nil {
			tc.Spec.PD.CanaryUpgrade.ClusterReadySeconds = pointer.Int32Ptr(defaultCanaryUpgradeClusterReadySeconds)
		}
		if tc.Spec.PD.CanaryUpgrade.StageReadySeconds == nil {
			tc.Spec.PD.CanaryUpgrade.StageReadySeconds = pointer.Int32Ptr(defaultCanaryUpgradeStageReadySeconds)
		}
	}
	if tc.Spec.PD.GroupName == nil {
		tc.Spec.PD.GroupName = pointer.StringPtr("")
	}
	if tc.Spec.PD.EnableUpgradeInNonReadyStates == nil {
		tc.Spec.PD.EnableUpgradeInNonReadyStates = pointer.BoolPtr(false)
	}
	if tc.Spec.PD.LeaderPriority == nil {
		tc.Spec.PD.LeaderPriority = pointer.Int32Ptr(0)
	}
}

func setPumpSpecDefault(tc *v1alpha1.TidbCluster) {
	if len(tc.Spec.Version) > 0 || tc.Spec.Pump.Version != nil {
		if tc.Spec.Pump.BaseImage == "" {
			tc.Spec.Pump.BaseImage = defaultBinlogImage
		}
	}
}

func setTiFlashSpecDefault(tc *v1alpha1.TidbCluster) {
	if len(tc.Spec.Version) > 0 || tc.Spec.TiFlash.Version != nil {
		if tc.Spec.TiFlash.BaseImage == "" {
			tc.Spec.TiFlash.BaseImage = defaultTiFlashImage
		}
	}
	if tc.Spec.TiFlash.MaxFailoverCount == nil {
		tc.Spec.TiFlash.MaxFailoverCount = pointer.Int32Ptr(3)
	}
	if tc.Spec.TiFlash.Failover != nil {
		if tc.Spec.TiFlash.Failover.ReplicasPerFailureStore == nil {
			tc.Spec.TiFlash.Failover.ReplicasPerFailureStore = pointer.Int32Ptr(1)
		}
	}
	if tc.Spec.TiFlash.EnablePVReclaim == nil {
		d := *tc.Spec.EnablePVReclaim
		tc.Spec.TiFlash.EnablePVReclaim = &d
	}
	if tc.Spec.TiFlash.PVReclaimDelayDuration == nil {
		tc.Spec.TiFlash.PVReclaimDelayDuration = pointer.StringPtr(defaultPVReclaimDelayDuration)
	}
	if tc.Spec.TiFlash.EnableConfigRollback == nil {
		tc.Spec.TiFlash.EnableConfigRollback = pointer.BoolPtr(false)
	}
	if tc.Spec.TiFlash.CanaryUpgrade != nil && pointer.BoolPtrDerefOr(tc.Spec.TiFlash.CanaryUpgrade.Enabled, false) {
		if tc.Spec.TiFlash.CanaryUpgrade.CoordinationSeconds == nil {
			tc.Spec.TiFlash.CanaryUpgrade.CoordinationSeconds = pointer.Int32Ptr(defaultCanaryUpgradeCoordinationSeconds)
		}
		if tc.Spec.TiFlash.CanaryUpgrade.ClusterReadySeconds == nil {
			tc.Spec.TiFlash.CanaryUpgrade.ClusterReadySeconds = pointer.Int32Ptr(defaultCanaryUpgradeClusterReadySeconds)
		}
		if tc.Spec.TiFlash.CanaryUpgrade.StageReadySeconds == nil {
			tc.Spec.TiFlash.CanaryUpgrade.StageReadySeconds = pointer.Int32Ptr(defaultCanaryUpgradeStageReadySeconds)
		}
	}
	if tc.Spec.TiFlash.AutoScaling != nil && pointer.BoolPtrDerefOr(tc.Spec.TiFlash.AutoScaling.Enabled, false) {
		if tc.Spec.TiFlash.AutoScaling.AllowScaleInCancel == nil {
			tc.Spec.TiFlash.AutoScaling.AllowScaleInCancel = pointer.BoolPtr(true)
		}
		if tc.Spec.TiFlash.AutoScaling.CPU != nil {
			if tc.Spec.TiFlash.AutoScaling.CPU.ScaleInReplicas == nil {
				tc.Spec.TiFlash.AutoScaling.CPU.ScaleInReplicas = pointer.Int32Ptr(defaultScaleInReplicas)
			}
			if tc.Spec.TiFlash.AutoScaling.CPU.ScaleOutReplicas == nil {
				tc.Spec.TiFlash.AutoScaling.CPU.ScaleOutReplicas = pointer.Int32Ptr(defaultScaleOutReplicas)
			}
			if tc.Spec.TiFlash.AutoScaling.CPU.ScaleInIntervalSeconds == nil {
				tc.Spec.TiFlash.AutoScaling.CPU.ScaleInIntervalSeconds = pointer.Int32Ptr(defaultScaleInIntervalSeconds)
			}
			if tc.Spec.TiFlash.AutoScaling.CPU.ScaleOutIntervalSeconds == nil {
				tc.Spec.TiFlash.AutoScaling.CPU.ScaleOutIntervalSeconds = pointer.Int32Ptr(defaultScaleOutIntervalSeconds)
			}
		}
		if tc.Spec.TiFlash.AutoScaling.Storage != nil {
			if tc.Spec.TiFlash.AutoScaling.Storage.ScaleInReplicas == nil {
				tc.Spec.TiFlash.AutoScaling.Storage.ScaleInReplicas = pointer.Int32Ptr(defaultScaleInReplicas)
			}
			if tc.Spec.TiFlash.AutoScaling.Storage.ScaleOutReplicas == nil {
				tc.Spec.TiFlash.AutoScaling.Storage.ScaleOutReplicas = pointer.Int32Ptr(defaultScaleOutReplicas)
			}
			if tc.Spec.TiFlash.AutoScaling.Storage.ScaleInIntervalSeconds == nil {
				tc.Spec.TiFlash.AutoScaling.Storage.ScaleInIntervalSeconds = pointer.Int32Ptr(defaultScaleInIntervalSeconds)
			}
			if tc.Spec.TiFlash.AutoScaling.Storage.ScaleOutIntervalSeconds == nil {
				tc.Spec.TiFlash.AutoScaling.Storage.ScaleOutIntervalSeconds = pointer.Int32Ptr(defaultScaleOutIntervalSeconds)
			}
		}
	}
	if tc.Spec.TiFlash.ScaleInProtection != nil && pointer.BoolPtrDerefOr(tc.Spec.TiFlash.ScaleInProtection.Enabled, false) {
		if tc.Spec.TiFlash.ScaleInProtection.StorageThreshold == nil {
			tc.Spec.TiFlash.ScaleInProtection.StorageThreshold = pointer.Float64Ptr(defaultScaleInProtectionStorageThreshold)
		}
		if tc.Spec.TiFlash.ScaleInProtection.MinReplicas == nil {
			tc.Spec.TiFlash.ScaleInProtection.MinReplicas = pointer.Int32Ptr(defaultScaleInProtectionMinReplicas)
		}
	}
	if tc.Spec.TiFlash.StoreLimit != nil && pointer.BoolPtrDerefOr(tc.Spec.TiFlash.StoreLimit.Enabled, false) {
		if tc.Spec.TiFlash.StoreLimit.UnbalanceThreshold == nil {
			tc.Spec.TiFlash.StoreLimit.UnbalanceThreshold = pointer.Float64Ptr(defaultStoreUnbalanceThreshold)
		}
		if tc.Spec.TiFlash.StoreLimit.NormalRate == nil {
			tc.Spec.TiFlash.StoreLimit.NormalRate = pointer.Float64Ptr(defaultStoreLimitRate)
		}
		if tc.Spec.TiFlash.StoreLimit.ScalingOutRate == nil {
			tc.Spec.TiFlash.StoreLimit.ScalingOutRate = pointer.Float64Ptr(defaultStoreLimitRate)
		}
		if tc.Spec.TiFlash.StoreLimit.ScalingInRate == nil {
			tc.Spec.TiFlash.StoreLimit.ScalingInRate = pointer.Float64Ptr(defaultStoreLimitRate)
		}
	}
	if tc.Spec.TiFlash.GroupName == nil {
		tc.Spec.TiFlash.GroupName = pointer.StringPtr("")
	}
	if tc.Spec.TiFlash.EnableUpgradeInNonReadyStates == nil {
		tc.Spec.TiFlash.EnableUpgradeInNonReadyStates = pointer.BoolPtr(false)
	}
	if tc.Spec.TiFlash.SupersedingCluster != nil {
		if tc.Spec.TiFlash.SupersedingCluster.Name != "" && tc.Spec.TiFlash.SupersedingCluster.Namespace == "" {
			tc.Spec.TiFlash.SupersedingCluster.Namespace = tc.GetNamespace()
		}
	}
	if tc.Spec.TiFlash.ComputeNode == nil {
		tc.Spec.TiFlash.ComputeNode = pointer.BoolPtr(false)
	}
}

func setTiCDCSpecDefault(tc *v1alpha1.TidbCluster) {
	if len(tc.Spec.Version) > 0 || tc.Spec.TiCDC.Version != nil {
		if tc.Spec.TiCDC.BaseImage == "" {
			tc.Spec.TiCDC.BaseImage = defaultTiCDCImage
		}
	}
}

func setTiProxySpecDefault(tc *v1alpha1.TidbCluster) {
	if len(tc.Spec.Version) > 0 || tc.Spec.TiProxy.Version != nil {
		if tc.Spec.TiProxy.BaseImage == "" {
			tc.Spec.TiProxy.BaseImage = defaultTiProxyImage
		}
	}
}
