package config

import (
	"fmt"

	apprent "github.com/tidbcloud/devops/entity/approval"
	ccent "github.com/tidbcloud/devops/entity/cloudconfig"
	"github.com/tidbcloud/devops/pkg/infra/errs"
	"github.com/tidbcloud/devops/pkg/infra/log"
)

type actorApproving struct {
	*baseActor
}

func (a *actorApproving) ContinueIfApproved() error {
	ctx := a.Context
	chg := a.Change

	if chg.ApprovalID == nil {
		return fmt.Errorf("phase is approving but approval id is nil")
	}

	appr, err := a.ApprovalService.GetApproval(ctx, *chg.ApprovalID)
	if err != nil {
		return fmt.Errorf("get approval '%d' failed: %s", *chg.ApprovalID, err)
	}

	switch appr.Status {
	case apprent.ApprovalStatusRejected, apprent.ApprovalStatusCancelled:
		// close this change if approval is withdrawn or canceled
		err := a.PatchConfigurationChange(ctx, PatchConfigurationChangeToClose(ccent.ConfigurationChangePhaseWithdrawn))
		if err != nil {
			return err
		}
	case apprent.ApprovalStatusApproved:
		// transition status to 'wait_for_apply'
		err := a.PatchConfigurationChange(ctx, func(current *ccent.ConfigurationChange) error {
			current.Phase = ccent.ConfigurationChangePhaseWaitForApply
			return nil
		})
		if err != nil {
			return err
		}
	default:
		return errs.RetriableErrorf("approval '%d' status is %s", *chg.ApprovalID, appr.Status)
	}

	return nil
}

func (a *actorApproving) Cancel() error {
	ctx := a.Context
	chg := a.Change

	if chg.ApprovalID != nil {
		err := a.ApprovalService.CancelApproval(ctx, *chg.ApprovalID)
		if err != nil {
			log.FromContext(ctx).Info("failed to cancel approval operation", "error", err)
		}
	}

	return a.cancel()
}
