package model

import (
	"time"

	"github.com/tidbcloud/pov-service/internal/common/constant"
)

type ScriptTypeDetail struct {
	Type   ScriptPhaseType `json:"type"`
	Detail any             `json:"detail"`
}

type ScriptPhase interface {
	GetName() string
	GetState() string
	GetDescription() string
	IsMutate() bool
	GetType() ScriptPhaseType
	GetTypeDetail() ScriptTypeDetail

	GetMessage() string
	GetStartDuration() time.Duration
	GetMutations() []ScriptMutation
}

type ScriptMutation struct {
	Param     constant.WorkloadParamName `json:"param"`
	Direction string                     `json:"direction,omitempty"`
	ToValue   string                     `json:"toValue"`
}

type ScriptMutatePhase struct {
	Name        string           `json:"name"`
	ID          int64            `json:"id"`
	State       string           `json:"state"`
	Description string           `json:"description"`
	Message     string           `json:"message"`
	Mutations   []ScriptMutation `json:"mutations"`
	// when to start this phase after the workload is started
	StartDuration time.Duration `json:"startDuration" swaggertype:"integer" format:"int64"`
}

func (s *ScriptMutatePhase) GetState() string {
	return s.State
}

func (s *ScriptMutatePhase) GetName() string {
	return s.Name
}

func (s *ScriptMutatePhase) GetDescription() string {
	return s.Description
}

func (s *ScriptMutatePhase) IsMutate() bool {
	return true
}

func (s *ScriptMutatePhase) GetType() ScriptPhaseType {
	return ScriptPhaseTypeMutate
}

func (s *ScriptMutatePhase) GetMessage() string {
	return s.Message
}

func (s *ScriptMutatePhase) GetStartDuration() time.Duration {
	return s.StartDuration
}

func (s *ScriptMutatePhase) GetMutations() []ScriptMutation {
	return s.Mutations
}

func (s *ScriptMutatePhase) GetTypeDetail() ScriptTypeDetail {
	direction := ""
	allUp := true
	allDown := true
	for _, m := range s.Mutations {
		if m.Direction == "down" {
			allUp = false
		}
		if m.Direction == "up" {
			allDown = false
		}
	}
	if allUp {
		direction = "up"
	} else if allDown {
		direction = "down"
	}

	return ScriptTypeDetail{
		Type: s.GetType(),
		Detail: struct {
			Diretion string `json:"diretion"`
		}{
			Diretion: direction,
		},
	}
}

type ScriptProceedPhase struct {
	Name          string        `json:"name"`
	ID            int64         `json:"id"`
	State         string        `json:"state"`
	Description   string        `json:"description"`
	Message       string        `json:"message"`
	StartDuration time.Duration `json:"startDuration" swaggertype:"integer" format:"int64"`
}

func (s *ScriptProceedPhase) GetState() string {
	return s.State
}

func (s *ScriptProceedPhase) GetName() string {
	return s.Name
}

func (s *ScriptProceedPhase) GetDescription() string {
	return s.Description
}
func (s *ScriptProceedPhase) IsMutate() bool {
	return false
}

func (s *ScriptProceedPhase) GetType() ScriptPhaseType {
	return ScriptPhaseTypeProceed
}

func (s *ScriptProceedPhase) GetTypeDetail() ScriptTypeDetail {
	return ScriptTypeDetail{
		Type: s.GetType(),
	}
}

func (s *ScriptProceedPhase) GetMessage() string {
	return s.Message
}

func (s *ScriptProceedPhase) GetStartDuration() time.Duration {
	return s.StartDuration
}

func (s *ScriptProceedPhase) GetMutations() []ScriptMutation {
	return nil
}

type ScriptSpec struct {
	Name          string        `json:"name"`
	Description   string        `json:"description"`
	TotalDuration time.Duration `json:"totalDuration" swaggertype:"integer" format:"int64"`
	Phases        []ScriptPhase `json:"phases"`
}

type ScriptSelector struct {
	WorkloadID  int64       `json:"workloadID"`
	ClusterType ClusterType `json:"clusterType"`
	// Dataset, Cluster...
}

// Script is the instance of a script template, with corresponding values.
// Script can be used by tuples including:
// - [MUST]Workload
// - [Optional] DataSet: different datasets may have different features that will affect the script value. e.g. whether the dataset has index
// - [Optional] Cluster: different clusters may have different features that will affect the script value. e.g. the plan or the region, or other companies' clusters.
// and this tuples are included in the ScriptSelector field.
type Script struct {
	ID           int64  `json:"id"`
	TemplateID   int64  `json:"templateId"`
	CreatorEmail string `json:"creatorEmail"`
	CreatedAt    time.Time
	UpdatedAt    time.Time
	ScriptSelector
	ScriptSpec
}

func (s Script) GetMutatePhases() []ScriptMutatePhase {
	ret := make([]ScriptMutatePhase, 0)
	for _, p := range s.Phases {
		if p.IsMutate() {
			ret = append(ret, *(p.(*ScriptMutatePhase)))
		}
	}
	return ret
}
