package task

import (
	"context"
	"fmt"

	"github.com/tidbcloud/pov-service/internal/model"
	"github.com/tidbcloud/pov-service/internal/pkg/log"
)

const (
	PhaseTransitionProcessorName = "phase-transition"
)

// PhaseTransitionProcessor handles transitioning between phases and completion
type PhaseTransitionProcessor struct {
	BaseProcessor
	hooks []PhaseTransitionHook
}

func NewPhaseTransitionProcessor(
	manager *ProcessorManager,
	hooks ...PhaseTransitionHook,
) *PhaseTransitionProcessor {
	ret := PhaseTransitionProcessor{BaseProcessor: BaseProcessor{manager}}
	ret.hooks = hooks
	return &ret
}

func (p *PhaseTransitionProcessor) GetName() string {
	return PhaseTransitionProcessorName
}

func (p *PhaseTransitionProcessor) CanProcess(test model.WorkloadTest, taskPhase model.WorkloadTaskPhase) bool {
	shouldFinishTest := (test.Phase == model.WorkloadTestPhaseRunWorkload && taskPhase == model.WorkloadTaskPhaseCompleted) ||
		taskPhase == model.WorkloadTaskPhaseFailed ||
		taskPhase == model.WorkloadTaskPhaseStopped

	shouldProceedTest := test.IsAuto && taskPhase == model.WorkloadTaskPhaseCompleted

	// Handle phase transitions when current task is completed or failed
	return test.IsOnTheFly() && (shouldFinishTest || shouldProceedTest)
}

func (p *PhaseTransitionProcessor) Process(ctx context.Context, test model.WorkloadTest) (model.WorkloadTest, error) {
	currentTask := test.CurrentPhaseTask()
	if currentTask == nil {
		return test, fmt.Errorf("no current task found")
	}

	fromPhase := test.Phase
	defer func() {
		go func() {
			for _, hook := range p.hooks {
				if hook.Match(fromPhase, test.Phase, test) {
					log.Log.Infof("Running phase transition hook %s for test %s", hook.GetName(), test.ID)
					err := hook.Do(ctx, test)
					if err != nil {
						log.Log.Errorf(err, "phase transition hook %s failed", hook.GetName())
					}
				}
			}
		}()
	}()

	// Handle failed tasks
	if currentTask.Phase == model.WorkloadTaskPhaseFailed {
		log.Log.Infof("Test %s failed at phase %s", test.ID, test.Phase)
		test.OnError(fmt.Errorf("task %s failed: %s", currentTask.Typ, currentTask.Message))

		return test, nil
	}

	// Handle stopped tasks
	if currentTask.Phase == model.WorkloadTaskPhaseStopped {
		log.Log.Infof("Test %s stopped at phase %s", test.ID, test.Phase)
		test.OnStop()

		return test, nil
	}

	// Handle completed tasks - transition to next phase
	switch test.Phase {
	case model.WorkloadTestPhaseCreateCluster:
		log.Log.Infof("Transitioning test %s from CreateCluster to PrepareData", test.ID)
		test.ProceedPrepareData()
	case model.WorkloadTestPhasePrepareData:
		log.Log.Infof("Transitioning test %s from PrepareData to RunWorkload", test.ID)
		test.ProceedRunTraffic()

	case model.WorkloadTestPhaseRunWorkload:
		log.Log.Infof("Test %s completed successfully", test.ID)
		test.OnComplete()
	}

	return test, nil
}
