package task

import (
	"context"
	"fmt"
	"time"

	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/tidbcloud/eks-provider/api/v1alpha1"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/consts"
	"github.com/tidbcloud/infra-provider/pkg/deploy"
	"github.com/tidbcloud/infra-provider/pkg/gitops"
	"github.com/tidbcloud/infra-provider/pkg/k8s"
	"github.com/tidbcloud/infra-provider/pkg/namer"
)

type Context struct {
	Remote k8s.ClientGetter
	Namer  *namer.Namer

	// Injected from the caller
	Local client.Client

	Dumpling *cloudv1.Dumpling

	Provider       gitops.Provider
	Network        *cloudv1.Network
	EKSNetworkSpec *v1alpha1.EKSNetworkSpec
	GKENetworkSpec *v1alpha1.GKENetworkSpec

	//BeginAt denotes the starting time of the task.
	BeginAt *time.Time

	TaskName string
	Image    string
}

func (c *Context) Default() (*Context, error) {
	c.Remote = &k8s.EmptyGetter{}

	c.Namer = namer.NewNamer().
		LegacyWithNetworkName(c.Network.Name).
		LegacyWithNetworkNamespace(c.Network.Namespace)

	providerType := c.Provider.GetProviderType()
	switch providerType {
	case consts.ProviderTypeEKS:
		networkSpec, err := v1alpha1.EKSNetworkSpecForNetwork(c.Network)
		if err != nil {
			return nil, fmt.Errorf("unable to get network spec: %v", err)
		}
		c.EKSNetworkSpec = networkSpec
	case consts.ProviderTypeGKE:
		networkSpec, err := v1alpha1.GKENetworkSpecForNetwork(c.Network)
		if err != nil {
			return nil, fmt.Errorf("unable to get network spec: %v", err)
		}
		c.GKENetworkSpec = networkSpec
	default:
		return nil, fmt.Errorf("unknown provider type: %s", providerType)
	}

	return c, nil
}

type BaseTask struct {
	*Context
}

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

func (t *BaseTask) Category() deploy.TaskCategory {
	return deploy.ClusterTask
}

func (t *BaseTask) Create(ctx context.Context) deploy.Result {
	return deploy.Done()
}

func (t *BaseTask) PostCreate(ctx context.Context) deploy.Result {
	return deploy.Done()
}

func (t *BaseTask) Delete(ctx context.Context) deploy.Result {
	return deploy.Done()
}

func (t *BaseTask) PostDelete(ctx context.Context) deploy.Result {
	return deploy.Done()
}

// MetricsStartTime will return the `BeginAt` (nil by default). For
// Task whose metrics need to be exported, the `BeginAt` should be
// initialized when the `Create` is being called.
func (t *BaseTask) MetricsStartTime() *time.Time {
	return t.Context.BeginAt
}
