package cloudconfig

import (
	"context"
	"fmt"
	"strconv"

	ccproto "github.com/tidbcloud/config-center/proto/config_center"
	ccent "github.com/tidbcloud/devops/entity/cloudconfig"
	"github.com/tidbcloud/devops/pkg/service/cloudconfig/change/common"
	"github.com/tidbcloud/devops/pkg/service/cloudconfig/cvt"
)

func (s *svc) GetClusterConfiguration(ctx context.Context, loc ccent.ClusterConfigurationLocator, mainComponent string) (*ccent.Configuration, error) {
	// 1. get cluster version
	getMetaReq := &ccproto.GetClusterMetaRequest{
		ClusterType:   cvt.To.ConfigCenter.ClusterType(loc.ClusterType),
		ClusterId:     loc.ClusterID,
		MainComponent: mainComponent,
	}

	var metaResp *ccproto.ClusterMeta
	var errr error
	switch getMetaReq.ClusterType {
	case ccproto.ClusterType_SHARED_POOL:
		getMetaReq.MainComponent = "tikv"
		clusterIDuint, err := strconv.ParseUint(loc.ClusterID, 10, 64)
		if err != nil {
			return nil, fmt.Errorf("invalid cluster ID for shared pool: %v", err)
		}
		rp, err := s.coreSvc.Mgmt.GetResourcePool(ctx, clusterIDuint)
		if err != nil {
			// legacy ui: use premium cluster in ui, convert to shared pool id in devops
			s.Logger(ctx).Info("resource pool not found, use premium id to route", "id", loc.ClusterID)
			mgmtCluster, err := s.coreSvc.Mgmt.GetCluster(ctx, clusterIDuint)
			if err != nil {
				return nil, fmt.Errorf("failed to get mgmt cluster info: %v", err)
			}
			getMetaReq.ClusterId = mgmtCluster.GetNextGenCluster().GetSharedPoolId()
			metaResp, errr = s.mgmtHTTP.ConfigCenterNgProxy().GetClusterMeta(ctx, loc.ClusterID, getMetaReq)
		} else {
			metaResp, errr = s.mgmtHTTP.ConfigCenterNgProxy().GetClusterMeta2(ctx, rp.GetRegion().GetLogicalName(), rp.GetRegion().GetCloudProviderId().String(), getMetaReq)
		}
	case ccproto.ClusterType_LOGICAL_CLUSTER:
		metaResp, errr = s.mgmtHTTP.ConfigCenterNgProxy().GetClusterMeta(ctx, loc.ClusterID, getMetaReq)
	case ccproto.ClusterType_TICDC:
		getMetaReq.MainComponent = ccproto.TICDC_COMPONENT_TICDC
		metaResp, errr = s.cfgCenter.ConfigAPI.GetClusterMeta(ctx, getMetaReq)
	default:
		metaResp, errr = s.cfgCenter.ConfigAPI.GetClusterMeta(ctx, getMetaReq)
	}
	if errr != nil {
		return nil, fmt.Errorf("failed to get cluster meta: %v", errr)
	}
	clusterVer := metaResp.Version

	result := &ccent.Configuration{
		TargetCluster: &loc,
		Version:       clusterVer,
		Components:    make(map[string]*ccent.Component),
		Files:         make(map[string]*ccent.FileConfiguration),
	}

	// 2. set components
	for _, compRaw := range metaResp.Components {
		comp := cvt.From.ConfigCenter.Component(compRaw)
		result.Components[comp.Name] = comp
	}

	// 3. merge attributes and cluster config to cluster parameters
	for _, rawCfgFile := range metaResp.ConfigurationFiles {
		curFilename := rawCfgFile.ConfigurationFilename
		curTmplID := uint64(rawCfgFile.TemplateId)
		builder := common.NewUnifiedParameterBuilder()

		// add template configs to parameters
		err := builder.InjectTemplates(ctx, s, loc.ClusterType, curTmplID)
		if err != nil {
			return nil, err
		}

		// add custom configs to parameters
		for key, cfgItem := range rawCfgFile.CustomParams {
			builder.AddCustom(cvt.From.ConfigCenter.NamedParameter(key, cfgItem))
		}

		// add attr to parameters
		err = builder.InjectAttrs(ctx, rawCfgFile.GetClusterType(), rawCfgFile.ConfigurationType, clusterVer, s.cfgCenter)
		if err != nil {
			return nil, err
		}

		result.Files[curFilename] = &ccent.FileConfiguration{
			Filename:          curFilename,
			ConfigType:        rawCfgFile.ConfigurationType,
			BelongToComponent: rawCfgFile.BelongToComponent,
			Format:            cvt.From.ConfigCenter.Format(rawCfgFile.Format),
			TemplateID:        curTmplID,
			Text:              rawCfgFile.Text,
			Parameters:        builder.Build(),
		}
	}

	return result, nil
}
