package planreplayer

import (
	"context"
	"time"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/clusterevent"
)

func (s *service) UpdatePlanReplayerStatus(
	ctx context.Context,
	req *globalngv1.UpdatePlanReplayerStatusRequest,
) (*globalngv1.PlanReplayerStatus, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "UpdatePlanReplayerStatus")
	defer span.End()

	if req == nil {
		return nil, bizerr.New(bizerr.ErrCodeParams, "request is required")
	}
	if req.GetClusterId() == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "cluster id is required")
	}

	cluster, err := s.clusterRepo.Get(ctx, req.GetClusterId(), false)
	if err != nil {
		return nil, err
	}
	if cluster == nil {
		return nil, bizerr.New(bizerr.ErrCodeRecordNotFound, "cluster not found")
	}

	if berr := validateServicePlan(cluster); berr != nil {
		return nil, berr
	}

	expireAt, hasExpireAt, berr := validatePatch(req.GetPlanReplayerStatus())
	if berr != nil {
		return nil, berr
	}

	var expireAtPtr *time.Time
	if hasExpireAt {
		expireAtPtr = &expireAt
	}

	if req.GetValidateOnly() {
		return buildStatus(cluster.ClusterId, expireAtPtr), nil
	}

	if err := s.transaction.Transaction(ctx, func(txCtx context.Context) error {
		cluster.PlanReplayerExpireAt = expireAtPtr
		if saveErr := s.clusterRepo.Save(txCtx, cluster); saveErr != nil {
			return saveErr
		}

		ev, eventErr := buildUpdateEvent(txCtx, cluster, req.GetPlanReplayerStatus().GetEnabled(), expireAtPtr)
		if eventErr != nil {
			return eventErr
		}

		if writeErr := s.eventCommitter.BatchWrite(txCtx, clusterevent.TopicClusterEvent, []clusterevent.Event{ev}); writeErr != nil {
			return bizerr.WrapErrorWithCode(writeErr, bizerr.ErrCodeUnknown, "write cluster event failed")
		}
		return nil
	}); err != nil {
		return nil, bizerr.WrapError(err, "update plan replayer status failed")
	}

	return buildStatus(cluster.ClusterId, expireAtPtr), nil
}
