package ruconfig

import (
	"fmt"
	"strings"

	apiv1 "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	"github.com/tidbcloud/cluster-service-ng/pkg/utils"
)

func isValid(c *entity.RuConfig) error {

	if c.Components == nil {
		return fmt.Errorf("components map is not initialized")
	}

	components := []apiv1.ComponentType{
		apiv1.ComponentType_PD,
		apiv1.ComponentType_PD_SCHEDULING,
		apiv1.ComponentType_PD_TSO,
		apiv1.ComponentType_TIKV,
		apiv1.ComponentType_TIKV_WORKER,
		apiv1.ComponentType_COPROCESSOR_WORKER,
		apiv1.ComponentType_TIDB,
		apiv1.ComponentType_TIDB_WORKER,
		apiv1.ComponentType_TIFLASH_COMPUTE,
		apiv1.ComponentType_TIFLASH_WRITE,
		apiv1.ComponentType_TIPROXY,
		apiv1.ComponentType_RESOURCE_MANAGER,
	}

	for _, compName := range components {

		compConfig := c.GetComponents()[strings.ToLower(compName.String())]

		if compConfig == nil {
			return fmt.Errorf("component %s has no RU ranges defined", compName.String())
		}

		hasZero := false
		maxNodeCount := compConfig.GetMaxNodeCount()
		if maxNodeCount == 0 {
			maxNodeCount = entity.DefaultNodeCountQuota
		}
		for nodeSpecStr, r := range compConfig.GetNodeSpecRuRange() {
			_, _, err := utils.ParseNodeSpec(nodeSpecStr)
			if err != nil {
				return fmt.Errorf("invalid node spec in component %s: %w", compName.String(), err)
			}

			maxRU := r.GetMax()
			if maxRU == 0 {
				// max ru is 0 means max is unlimited
				maxRU = 0xffffffff // use a large number to represent unlimited
			}

			if maxRU <= r.GetMin() {
				return fmt.Errorf("invalid range in component %s: max must be greater than min", compName.String())
			}

			if err := entity.ValidateDefaultNodeCount(compName, r.DefaultNodeCount, maxNodeCount); err != nil {
				return fmt.Errorf("invalid default node count in component %s: %w", compName.String(), err)
			}

			if r.GetMin() == 0 {
				hasZero = true
			}
		}

		// at least one range must start from 0
		if !hasZero {
			return fmt.Errorf("component %s must have a range starting from 0", compName.String())
		}
	}

	return nil
}

// fillDefaultOptionalComponents fills in default configurations for optional components
// if they are not present in the ruConfig. This ensures backward compatibility
// when new optional components are added.
func fillDefaultOptionalComponents(c, defaultConfig *entity.RuConfig) {
	if c.Components == nil {
		c.Components = make(map[string]*entity.RuConfigComponentsMap)
	}

	// resource_manager: use default config if not present
	resourceManagerKey := strings.ToLower(apiv1.ComponentType_RESOURCE_MANAGER.String())
	if _, ok := c.Components[resourceManagerKey]; !ok {
		if defaultCfg, exists := defaultConfig.GetComponents()[resourceManagerKey]; exists {
			c.Components[resourceManagerKey] = defaultCfg
		}
	}
}
