package task

import (
	"context"
	"time"

	"github.com/go-logr/logr"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/cloud/aws"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/config"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/consts"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/deploy"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/namer"
)

const (
	Finalizer = v1alpha1.Finalizer
)

type Context struct {
	Scheme           *runtime.Scheme
	Local            client.Client
	Logger           logr.Logger
	Config           config.RootConfig
	Namer            *namer.Namer
	NodePool         *v1alpha1.NodePool
	DataPlane        *v1alpha1.DataPlane
	APPBox           *v1alpha1.APPBox
	VPC              *v1alpha1.VPC
	AWSClient        aws.Client
	AWSAMITypeGetter aws.AMITypeGetter
	BeginAt          *time.Time
}

var _ deploy.Task = &BaseTask{}

func (c *Context) Default() (*Context, error) {
	n := namer.NewNamer()
	if c.VPC != nil && c.APPBox != nil {
		n = n.LegacyWithNetworkName(c.VPC.Name).
			LegacyWithNetworkNamespace(c.VPC.Namespace).
			WithAPPBoxName(c.APPBox.Name)
	}
	c.Namer = n
	return c, nil
}

func (c *Context) ProviderConfigName() string {
	if c.VPC == nil || c.VPC.Spec.AccountRef == nil {
		return ""
	}
	return c.VPC.Spec.AccountRef.ProviderConfigName
}

func (c *Context) RoleARN() string {
	if c.VPC == nil || c.VPC.Spec.AccountRef == nil {
		return ""
	}
	switch c.VPC.Spec.Provider {
	case consts.ProviderTypeACK:
		return "acs:ram::" + c.VPC.Spec.AccountRef.AccountID + ":role/" + c.VPC.Spec.AccountRef.Role
	case consts.ProviderTypeEKS:
		return "arn:aws:iam::" + c.VPC.Spec.AccountRef.AccountID + ":role/" + c.VPC.Spec.AccountRef.Role
	}
	return ""
}

func (c *Context) MetricsStartTime() *time.Time {
	return c.BeginAt
}

// GetNodeZones returns effective node AZs for nodepool-related resources.
//
// Priority:
//  1. VPC.Spec.NodeZones
//  2. VPC.Spec.Zones
func (c *Context) GetNodeZones() []string {
	if c.VPC == nil {
		return nil
	}
	if len(c.VPC.Spec.NodeZones) > 0 {
		return append([]string(nil), c.VPC.Spec.NodeZones...)
	}
	return append([]string(nil), c.VPC.Spec.Zones...)
}

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
}
