package common

import (
	"context"
	"fmt"
	"time"

	clusterctlpb "github.com/tidbcloud/infra-provider/api/tidbcloud/cluster-server/v1"
	"github.com/tidbcloud/infra-provider/pkg/deploy"
	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/controllers/privatelinkservice/task"
)

type LoadBalancer struct {
	*task.BaseTask
}

func NewLoadBalancer(ctx *task.Context) *LoadBalancer {
	return &LoadBalancer{&task.BaseTask{Context: ctx}}
}

func (l *LoadBalancer) Name() string {
	return "LoadBalancer"
}

func (l *LoadBalancer) Create(ctx context.Context) deploy.Result {
	targetLbs := l.PrivateLinkService.Spec.LoadBalancers
	lbStatus := []v1alpha1.LoadBalancerStatus{}
	allReady := true
	for _, lb := range targetLbs {
		info, err := l.ClusterCli.GetTidbGroup(ctx, &clusterctlpb.GetTidbGroupRequest{
			ClusterId:   lb.ClusterID,
			TidbGroupId: lb.ID,
		})
		if err != nil {
			l.Logger.Error(err, "get loadbalancer failed", "clusterId", lb.ClusterID, "loadbalancerId", lb.ID)
			return deploy.Panic(err).WithRequeuAfter(time.Second * 30)
		}
		if info == nil {
			l.Logger.Error(nil, "loadbalancer not found", "clusterId", lb.ClusterID, "loadbalancerId", lb.ID)
			return deploy.Panic(fmt.Errorf("loadbalancer not found, clusterId: %s, loadbalancerId: %s", lb.ClusterID, lb.ID)).WithRequeuAfter(time.Second * 30)
		}
		if !info.EnablePrivateLb || info.PrivateLb == nil {
			l.Logger.Error(nil, "private loadbalancer not found", "clusterId", lb.ClusterID, "loadbalancerId", lb.ID)
			return deploy.Panic(fmt.Errorf("private loadbalancer not found, clusterId: %s, loadbalancerId: %s", lb.ClusterID, lb.ID)).WithRequeuAfter(time.Second * 30)
		}
		phase := v1alpha1.LoadBalancerPhaseActive
		if info.PrivateLb.Host == "" || info.PrivateLb.CloudResourceId == "" {
			l.Logger.Info("loadbalancer is not ready", "clusterId", lb.ClusterID, "loadbalancerId", lb.ID, "host", info.PrivateLb.Host, "cloudResourceId", info.PrivateLb.CloudResourceId)
			allReady = false
			phase = v1alpha1.LoadBalancerPhaseCreating
		}
		lbStatus = append(lbStatus, v1alpha1.LoadBalancerStatus{
			ID:              lb.ID,
			CloudResourceId: info.PrivateLb.CloudResourceId,
			Port:            info.PrivateLb.Port,
			Host:            info.PrivateLb.Host,
			Type:            clusterctlpb.LoadBalancer_PRIVATE.String(),
			Phase:           phase,
		})

		l.PrivateLinkService.Status.DNSIdentify = info.ClusterIdentifierHash
	}

	l.PrivateLinkService.Status.LoadBalancers = lbStatus
	if err := l.PrivateLinkServiceRW.UpdateStatus(ctx, l.PrivateLinkService); err != nil {
		return deploy.Panic(err).WithRequeuAfter(time.Second * 30)
	}

	if !allReady {
		return deploy.Panic(fmt.Errorf("loadbalancer is not ready")).WithRequeuAfter(time.Second * 30)
	}

	return deploy.Done()
}
