package dataplanemanager

import (
	"context"

	apiv1 "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	dplanemgrv1 "github.com/tidbcloud/cluster-service-ng/api/dataplane-manager/v1"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	"github.com/tidbcloud/cluster-service-ng/pkg/dataplanemgr"
	"github.com/tidbcloud/cluster-service-ng/pkg/storage/repo"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type dataplaneRepoImpl struct {
	cloudProvider   string
	region          string
	dataplaneClient dataplanemgr.Client
}

func NewDataplaneRepo(
	region string,
	cloudProvider string,
	client dataplanemgr.Client,
) (repo.DataplaneRepo, error) {
	return &dataplaneRepoImpl{
		region:          region,
		cloudProvider:   cloudProvider,
		dataplaneClient: client,
	}, nil
}

// access dataplane info from dataplane manager
func (d *dataplaneRepoImpl) LoadByName(ctx context.Context, name string) (*entity.DataPlaneProvider, error) {
	in := new(dplanemgrv1.GetDataPlaneRequest)
	in.DataPlaneId = name
	out, err := d.dataplaneClient.GetDataPlaneServiceClient().GetDataPlane(ctx, in)
	if err != nil {
		return nil, err
	}

	// Build provider object first so we can return partial info for Creating status
	provider := new(entity.DataPlaneProvider)
	provider.Name = out.GetId()
	provider.Version = out.GetKubernetes().GetVersion()
	provider.IdentityId = out.GetAccountId()
	provider.NodeRole = out.GetNodeRole()
	provider.NodeClientId = out.GetNodeClientId()
	provider.Type = d.providerType()
	provider.Region = d.region
	provider.NodeZones = out.GetNodeZones()
	provider.Kubeconfig = out.GetKubernetes().GetKubeconfig()
	provider.GatewayUrl = out.GetApiGateway()
	provider.AuthToken = out.GetAuthToken()
	provider.Tags = out.GetTags()

	// Handle Creating status: return provider with NotFound error so caller can use partial info
	if out.Status == dplanemgrv1.DataPlane_Creating {
		return provider, status.Errorf(codes.NotFound, "dataplane %s is still creating", name)
	}

	// Handle other non-Active statuses (e.g., Deleting, Failed)
	if out.Status != dplanemgrv1.DataPlane_Active {
		return nil, status.Errorf(codes.Unavailable, "dataplane %s is not active, current status: %s", name, out.Status.String())
	}

	// FIXME(shenjun): some fields are missing
	return provider, nil
}

func (d *dataplaneRepoImpl) providerType() entity.ProviderType {
	switch d.cloudProvider {
	case "aws", "AWS":
		return apiv1.ProviderType_AWS
	case "gcp", "GCP":
		return apiv1.ProviderType_GCP
	case "azure", "AZURE":
		return apiv1.ProviderType_AZURE
	case "alicloud", "ALICLOUD":
		return apiv1.ProviderType_ALICLOUD
	}
	return apiv1.ProviderType_PROVIDER_TYPE_UNSPECIFIED
}
