package cloudconfig

import (
	"context"
	"fmt"

	ccent "github.com/tidbcloud/devops/entity/cloudconfig"
	"github.com/tidbcloud/devops/pkg/infra/utils/container"
	"github.com/tidbcloud/devops/pkg/infra/utils/pointer"
	"github.com/tidbcloud/devops/pkg/service/cloudconfig/api"
	"github.com/tidbcloud/devops/pkg/service/cloudconfig/cvt"
	"google.golang.org/protobuf/types/known/structpb"

	ccproto "github.com/tidbcloud/config-center/proto/config_center"
)

func (s *svc) GetParameterAttribute(ctx context.Context, clusterType, configType, version, name string) (*ccent.ParameterAttribute, error) {
	req := ccproto.GetConfigurationDictItemRequest{
		ClusterType:         ccproto.ClusterType(ccproto.ClusterType_value[clusterType]),
		ConfigurationType:   configType,
		Version:             version,
		ParamKey:            name,
		MatchPartialVersion: true,
	}

	resp, err := s.cfgCenter.ConfigAPI.GetConfigurationDictItem(ctx, &req)
	if err != nil {
		return nil, fmt.Errorf("failed to get param attr from config dict: %w", err)
	}

	attr := cvt.From.ConfigCenter.ParameterAttribute(resp)
	return attr, nil
}

func (s *svc) ListParameterAttribute(ctx context.Context, param api.ListParamAttributesParam) ([]*ccent.ParameterAttribute, int64, error) {
	req := ccproto.ListConfigurationDictItemsRequest{
		ClusterType:         ccproto.ClusterType(ccproto.ClusterType_value[param.ClusterType]),
		ConfigurationType:   &param.ConfigType,
		MatchPartialVersion: true,
	}

	if param.VersionIs != nil {
		req.Version = param.VersionIs
	}
	if param.NameLike != nil {
		req.ParamKeyLike = param.NameLike
	}
	if len(param.NameIn) > 0 {
		req.ParamKeyIn = param.NameIn
	}
	req.Page = param.Page
	req.PageSize = param.PerPage

	resp, err := s.cfgCenter.ConfigAPI.ListConfigurationDictItems(ctx, &req)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to list param attrs from config dict: %w", err)
	}

	attrs := container.TransformSlice(resp.ConfigurationDictItems, cvt.From.ConfigCenter.ParameterAttribute)
	return attrs, resp.Total, nil
}

func (s *svc) CreateParameterAttribute(ctx context.Context, attr ccent.ParameterAttribute) error {
	attrInProto, err := cvt.To.ConfigCenter.ParameterAttribute(attr)
	if err != nil {
		return fmt.Errorf("failed to convert param attr to config center: %w", err)
	}

	req := &ccproto.BatchCreateConfigurationDictRequest{
		ConfigurationDictItems: []*ccproto.ConfigurationDictItem{attrInProto},
	}
	_, err = s.cfgCenter.ConfigAPI.BatchCreateConfigurationDictItems(ctx, req)
	return err
}

func (s *svc) UpdateParameterAttribute(ctx context.Context, clusterType, configType, version, name string, param api.UpdateParamterAttributeParam) error {
	req := &ccproto.UpdateConfigurationDictItemReq{
		ClusterType:       ccproto.ClusterType(ccproto.ClusterType_value[clusterType]),
		ConfigurationType: configType,
		Version:           version,
		ParamKey:          name,
		Validation:        param.Validation,
		UpdatedBy:         param.UpdatedBy,
	}

	if param.ApplyPolicy != nil {
		req.HotReloadable = pointer.Pointer(cvt.To.ConfigCenter.ParameterApplyPolicy(*param.ApplyPolicy))
	}
	if param.DefaultValue != nil {
		val, err := structpb.NewValue(*param.DefaultValue)
		if err != nil {
			return fmt.Errorf("failed to set param default value: %w", err)
		}
		req.DefaultValue = val
	}
	if param.Description != nil {
		req.Description = param.Description
	}
	if param.RiskLevel != nil {
		req.RiskLevel = pointer.Pointer(string(*param.RiskLevel))
	}

	_, err := s.cfgCenter.ConfigAPI.UpdateConfigurationDictItem(ctx, req)
	return err
}

func (s *svc) CloneParameterAttributes(ctx context.Context, fromVersion, toVersion string) error {
	req := &ccproto.CopyConfigurationDictFromOldVersionRequest{
		FromVersion: fromVersion,
		ToVersion:   toVersion,
	}
	_, err := s.cfgCenter.ConfigAPI.CopyConfigurationDictFromOldVersion(ctx, req)
	return err
}
