package scripttask

import (
	"context"
	"encoding/json"

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

type sqlMutateProcessor struct {
	svc service.Workload
}

func (s sqlMutateProcessor) Process(
	ctx context.Context,
	exec model.ScriptExec,
	mut model.ScriptMutation,
) error {
	return s.svc.InstructWorkloadTest(
		ctx, exec.TestID, params.InstructWorkloadTest{
			SQLStatement: mut.ToValue,
		})

}

type injectFailureMutateProcessor struct {
	svc service.Workload
}

func (s injectFailureMutateProcessor) Process(
	ctx context.Context,
	exec model.ScriptExec,
	mut model.ScriptMutation,
) error {
	// Parse JSON from ToValue to extract duration
	var failureParams struct {
		Duration string `json:"duration"`
	}
	if err := json.Unmarshal([]byte(mut.ToValue), &failureParams); err == nil {
		if err = s.svc.InjectFailure(ctx, exec.TestID, failureParams.Duration); err != nil {
			log.Log.Errorf(err, "failed to inject failure for workload test %s using script %s", exec.TestID, exec.ID)
			return err
		}
	} else {
		log.Log.Errorf(err, "failed to parse inject failure parameters for script %s", exec.ID)
		return err
	}
	return nil
}

type rollbackFailureMutateProcessor struct {
	svc service.Workload
}

func (s rollbackFailureMutateProcessor) Process(
	ctx context.Context,
	exec model.ScriptExec,
	mut model.ScriptMutation,
) error {
	// Call RollbackFailure method
	err := s.svc.RollbackFailure(ctx, exec.TestID)
	if err != nil {
		log.Log.Errorf(err, "failed to rollback failure for workload test %s using script %s", exec.TestID, exec.ID)
	}

	return err
}

func newInstructMutateProcessor(
	svc service.Workload,
	param constant.WorkloadParamName,
) ScriptMutateProcessor {
	switch param {
	case constant.InjectFailure:
		return injectFailureMutateProcessor{svc: svc}
	case constant.RollbackFailure:
		return rollbackFailureMutateProcessor{svc: svc}
	case constant.SQLStatement:
		return sqlMutateProcessor{svc: svc}
	}

	return nil
}
