package provider

import (
	"context"
	"errors"
	"fmt"
	"net/http"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/compat/common"
	models "github.com/tidbcloud/infra-provider/pkg/compat/models"
	"github.com/tidbcloud/tiinf/transport/crossregion"
	apperror "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

const (
	errNoneProviderType = "none provider type"
	providerurl         = "/inner/mgmt/compat/v1/providers/%s"
)

func toProviderRegion(regions []models.CompatProviderCompatRegion) []cloudv1.Region {
	var result []cloudv1.Region
	for _, region := range regions {
		result = append(result, cloudv1.Region{
			Name:  region.Name,
			Zones: region.Zones,
		})
	}
	return result
}

type CompatProviderClienter interface {
	GetProvider(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error
}

type CompatProviderClient struct {
	Env crossregion.EnvType
}

func NewCompatProviderClient(env crossregion.EnvType) *CompatProviderClient {
	return &CompatProviderClient{
		Env: env,
	}
}

func (cpc CompatProviderClient) GetProvider(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
	provider, ok := obj.(*cloudv1.Provider)
	if !ok {
		return apperror.NewInternalError(errors.New(errNoneProviderType))
	}
	resp, code, err := common.GetGlobalHTTP[models.V1CompatProvider](ctx, cpc.Env, providerurl, key.Name, nil)
	if err != nil {
		return apperror.NewInternalError(err)
	}
	if code == http.StatusNotFound || resp == nil {
		return apperror.NewNotFound(schema.GroupResource{
			Group:    obj.GetObjectKind().GroupVersionKind().Group,
			Resource: obj.GetObjectKind().GroupVersionKind().Kind,
		}, key.Name)
	}
	if code != http.StatusOK {
		return apperror.NewInternalError(fmt.Errorf("call global cluster failed, code=%d", code))
	}
	//we only merge new path region and zone to old path provider
	provider.Spec.Regions = toProviderRegion(resp.Regions)
	return nil
}
