package task

import (
	"context"
	"time"

	"github.com/go-logr/logr"
	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
	observabilitypingcapcomv1 "github.com/tidbcloud/observability/api/regionalserver/resourceworker/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/tidbcloud/observability/pkg/common/deploy"
	"github.com/tidbcloud/observability/pkg/common/structs"
)

const (
	Finalizer = "observability.pingcap.com/Cluster"
)

type Context struct {
	Cluster  *observabilitypingcapcomv1.Cluster
	original *observabilitypingcapcomv1.Cluster
	// Injected from the caller
	Logger logr.Logger
	// Local refers to RDS Client.
	Local client.Client
	// Remote refers to O11y Regional Server.
	Remote client.Client
	Config structs.ServiceInfo
	// BeginAt denotes the starting time of the task.
	BeginAt *time.Time
}

func (c *Context) Default() (*Context, error) {
	c.original = c.Cluster.DeepCopy()
	return c, nil
}

func (c *Context) IsClusterChanged() bool {
	diff := cmp.Diff(c.original, c.Cluster, cmpopts.EquateEmpty())
	if diff == "" {
		c.Logger.Info("cluster is synced")
		return false
	}
	c.Logger.Info("cluster is not synced", "diff", diff)
	return true
}

func (t *Context) SetRemoteClient(ctx context.Context) error {
	return nil
}

var _ deploy.Task = &BaseTask{}

type BaseTask struct {
	*Context
}

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

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

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
}
