package task

import (
	"context"
	"fmt"
	"time"

	"github.com/go-logr/logr"
	"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/namer"
)

const Finalizer = "networkpeer.cloud.pingcap.com/finalizer"

type Context struct {
	Local client.Client
	Namer *namer.Namer

	Logger logr.Logger

	ProviderType string

	NetworkPeer *cloudv1.NetworkPeer
	Network     *cloudv1.Network

	EKSNetworkSpec *v1alpha1.EKSNetworkSpec
	GKENetworkSpec *v1alpha1.GKENetworkSpec

	TargetNetwork        *cloudv1.Network
	TargetEKSNetworkSpec *v1alpha1.EKSNetworkSpec
	TargetGKENetworkSpec *v1alpha1.GKENetworkSpec

	BeginAt *time.Time
}

func (c *Context) Default() (*Context, error) {
	c.Namer = namer.NewNamer().
		LegacyWithNetworkName(c.Network.Name)

	switch c.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

		if c.TargetNetwork != nil {
			targetNetworkSpec, err := v1alpha1.EKSNetworkSpecForNetwork(c.TargetNetwork)
			if err != nil {
				return nil, fmt.Errorf("unable to get target network spec: %v", err)
			}
			c.TargetEKSNetworkSpec = targetNetworkSpec
		}

	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

		if c.TargetNetwork != nil {
			targetNetworkSpec, err := v1alpha1.GKENetworkSpecForNetwork(c.TargetNetwork)
			if err != nil {
				return nil, fmt.Errorf("unable to get target network spec: %v", err)
			}
			c.TargetGKENetworkSpec = targetNetworkSpec

		}

	default:
		return nil, fmt.Errorf("unknown provider type: %s", c.ProviderType)
	}

	return c, nil
}

var _ deploy.Task = &BaseTask{}

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()
}

func (t *BaseTask) MetricsStartTime() *time.Time {
	return t.BeginAt
}
