package actors

import (
	"fmt"
	"time"

	"github.com/tidbcloud/devops/entity"
	apprent "github.com/tidbcloud/devops/entity/approval"
	"github.com/tidbcloud/devops/pkg/infra/errs"
	"github.com/tidbcloud/devops/pkg/infra/utils/pointer"
	rmapi "github.com/tidbcloud/devops/pkg/service/remediationticket/api"
	rmrepo "github.com/tidbcloud/devops/pkg/service/remediationticket/repo"
)

type actorApproving struct {
	*baseActor
}

func (a *actorApproving) GetContext() *Context {
	return a.Context
}

func (a *actorApproving) ContinueIfApproved() error {
	ctx := a.Context
	ins := a.RemediationTicket

	if ins.ApprID == 0 {
		return fmt.Errorf("phase is approving but approval id is nil")
	}

	opt := rmrepo.RemediationTicketPhaseApprovalOpts.ApprovalIDIs(ins.ApprID)
	ticketApprovals, err := ctx.RemediationTicketRepo.QueryTicketPhaseApproval(ctx, opt)
	if err != nil {
		return fmt.Errorf("get ticket approval for appr id %d failed: %w", ins.ApprID, err)
	}
	if len(ticketApprovals) == 0 {
		return fmt.Errorf("cannot find ticket approval for appr id %d", ins.ApprID)
	}

	// redundant validation, shouldn't be here
	if ticketApprovals[0].TicketId != ins.ID {
		return fmt.Errorf("integrity error: ticket approval record does not match ticket record")
	}

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

	switch appr.Status {
	case apprent.ApprovalStatusRejected, apprent.ApprovalStatusCancelled:
		return a.PatchRemediationTicket(ctx, func(current *entity.RemediationTicket) error {
			current.Status = entity.RemediationTicketStatusRejected
			return nil
		})
	case apprent.ApprovalStatusApproved:
		// transition to next phase
		err = a.PatchRemediationTicket(ctx, func(current *entity.RemediationTicket) error {
			current.Phase = &ticketApprovals[0].ToPhase
			current.Status = entity.RemediationTicketStatusPending
			return nil
		})
		if err != nil {
			return err
		}
		return nil
	}

	return errs.RetriableErrorf("approval '%d' is still %s", ins.ApprID, appr.Status)
}

func (a *actorApproving) Cancel() error {
	return a.cancel()
}

func (a *actorApproving) SendApproval(rmapi.TransferTicketParam) error {
	return a.defaultErr
}

func (a *actorApproving) cancel() error {
	ctx := a.Context

	apprID := ctx.Origin.ApprID
	if apprID != 0 {
		err := a.GetContext().ApprovalService.CancelApproval(ctx, apprID)
		if err != nil {
			return err
		}
	}

	// transition status to 'Cancel'
	return a.PatchRemediationTicket(ctx,
		func(current *entity.RemediationTicket) error {
			phase := entity.RemediationTicketPhaseClosed
			status := entity.RemediationTicketStatusClosed
			current.Phase = &phase
			current.Status = status
			current.ClosedAt = pointer.Pointer(time.Now().Unix())
			return nil
		})
}
