package resourcemanager

import (
	"context"

	v1 "github.com/tidbcloud/observability/api/regionalserver/resourceworker/v1"
	"github.com/tidbcloud/observability/pkg/common/constants"
	"github.com/tidbcloud/observability/pkg/common/errors"
	"github.com/tidbcloud/observability/pkg/common/message"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

type integrationTaskReaderWriter struct {
	cli client.Client
}

func (p integrationTaskReaderWriter) CreateIntegrationTask(ctx context.Context, data *v1.IntegrationTask) error {
	err := p.cli.Create(ctx, data)
	if err != nil {
		return WrapClientError(err)
	}
	return nil
}

func (p integrationTaskReaderWriter) GetIntegrationTask(ctx context.Context, key client.ObjectKey) (*v1.IntegrationTask, error) {
	task := &v1.IntegrationTask{}
	err := p.cli.Get(ctx, key, task)

	if err != nil {
		if client.IgnoreNotFound(err) == nil {
			return nil, errors.NewErrorf(errors.IntegrationTaskNotFound, "integration task %s is not found", key)
		}
		return nil, WrapClientError(err)
	}

	return task, nil
}

func (p integrationTaskReaderWriter) GetIntegrationTaskByID(ctx context.Context, clusterId, taskId string) (*v1.IntegrationTask, error) {
	tasks, err := p.ListIntegrationTasks(ctx, client.MatchingLabels{
		constants.LabelIntegrationTaskID: taskId,
		constants.LabelApplicationID:     clusterId,
	})

	if err != nil {
		return nil, WrapClientError(err)
	}
	if len(tasks.Items) == 0 {
		return nil, errors.NewErrorf(errors.IntegrationTaskNotFound, "integration task %s is not found", taskId)
	}

	return &tasks.Items[0], nil
}

func (p integrationTaskReaderWriter) IsIntegrationTaskExists(ctx context.Context, key client.ObjectKey) (bool, error) {
	task := &v1.IntegrationTask{}
	err := p.cli.Get(ctx, key, task)

	if err != nil {
		if client.IgnoreNotFound(err) == nil {
			return false, nil
		}
		return false, WrapClientError(err)
	}

	return true, nil
}

func (p integrationTaskReaderWriter) QueryIntegrationTasks(ctx context.Context, filters map[string]string, cr message.ContinueRequest) (*v1.IntegrationTaskList, error) {
	tasks := new(v1.IntegrationTaskList)

	listOptions := []client.ListOption{}

	// Add label selectors for filtering
	if len(filters) > 0 {
		listOptions = append(listOptions, client.MatchingLabels(filters))
	}

	// Add pagination options
	if cr.Limit > 0 {
		listOptions = append(listOptions, client.Limit(cr.Limit))
	}
	if cr.ContinueToken != "" {
		listOptions = append(listOptions, client.Continue(cr.ContinueToken))
	}

	err := p.cli.List(ctx, tasks, listOptions...)
	return tasks, WrapClientError(err)
}

func (p integrationTaskReaderWriter) ListIntegrationTasks(ctx context.Context, opts ...client.ListOption) (*v1.IntegrationTaskList, error) {
	tasks := new(v1.IntegrationTaskList)
	if err := p.cli.List(ctx, tasks, opts...); err != nil {
		return nil, WrapClientError(err)
	}
	return tasks, nil
}

func (p integrationTaskReaderWriter) UpdateIntegrationTask(ctx context.Context, data *v1.IntegrationTask) error {
	return WrapClientError(p.cli.Update(ctx, data))
}

func (p integrationTaskReaderWriter) DeleteIntegrationTask(ctx context.Context, key client.ObjectKey) error {
	return WrapClientError(p.cli.Delete(ctx, &v1.IntegrationTask{
		ObjectMeta: metav1.ObjectMeta{
			Name:      key.Name,
			Namespace: key.Namespace,
		},
	}))
}
