package gke

import (
	"context"
	"crypto/md5"
	"fmt"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"

	"github.com/tidbcloud/eks-provider/controllers/network/task"
	"github.com/tidbcloud/infra-provider/pkg/cloud/gcp"
	"github.com/tidbcloud/infra-provider/pkg/deploy"
)

const (
	pscNameHashSize = 8
)

// GoogleApiPsc deploys the Google API PSC for all components to access google api.
type GoogleApiPsc struct {
	*task.BaseTask
	gcpCli gcp.Client
}

var _ deploy.Task = &GoogleApiPsc{}

func NewGoogleApiPsc(ctx *task.Context, gcpCli gcp.Client) *GoogleApiPsc {
	return &GoogleApiPsc{
		BaseTask: &task.BaseTask{Context: ctx},
		gcpCli:   gcpCli,
	}
}

func (t *GoogleApiPsc) Name() string {
	return "GoogleApiPsc"
}

func (t *GoogleApiPsc) Create(ctx context.Context) deploy.Result {
	project := t.GKENetworkSpec.ProjectID
	region := t.Network.Spec.Region
	network := t.GKENetworkSpec.Network
	name := googleApiPscName(t.Network)
	tags := cloudv1.TagsFromLabels(t.Network.Labels)

	if t.IsMigrate {
		exists, err := t.gcpCli.IsGoogleApiPscExists(ctx, project, network)
		if err != nil {
			return deploy.Error(err)
		}
		if exists {
			return deploy.Done()
		}
	}

	if err := t.gcpCli.CreateGoogleApiPsc(ctx, project, region, network, name, tags); err != nil {
		return deploy.Error(err)
	}
	return deploy.Done()
}

func (t *GoogleApiPsc) Delete(ctx context.Context) deploy.Result {
	project := t.GKENetworkSpec.ProjectID
	name := googleApiPscName(t.Network)
	if err := t.gcpCli.DeleteGoogleApiPsc(ctx, project, name); err != nil {
		return deploy.Error(err)
	}
	return deploy.Done()
}

// The forwarding rule name for PSC Google APIs must be an 1-20 characters string with lowercase letters and numbers and must start with a letter.
// The address name must start with a lowercase letter followed by up to 62 lowercase letters, numbers, or hyphens, and cannot end with a hyphen.
func googleApiPscName(network *cloudv1.Network) string {
	namespacedName := fmt.Sprintf("%s/%s", network.GetNamespace(), network.GetName())
	hash := fmt.Sprintf("%x", md5.Sum([]byte(namespacedName)))[:pscNameHashSize]
	// gapipsc means Google API PSC.
	return fmt.Sprintf("gapipsc%s", hash)
}
