package entity

import (
	"time"

	"github.com/tidbcloud/chaos-svc/idl/pbgen/proto/chaos"
	"github.com/tidbcloud/chaos-svc/pkg/domain/constant"
	"github.com/tidbcloud/chaos-svc/pkg/domain/vo"
)

type Workflow struct {
	ID          uint64
	ProjectID   uint64
	ClusterID   uint64
	Draft       bool
	Status      chaos.ExperimentStatus
	Message     string
	Spec        WorkflowSpec
	Nodes       map[string]*vo.WorkflowNode
	CreatedByID uint64
	CreatedAt   time.Time
	StartedAt   *time.Time
	CompletedAt *time.Time
	DeletedAt   *time.Time
	ReportLink  string
	Summary     string
	Versioning  int
}

type WorkflowSpec struct {
	EntryNodeName string                          `json:"entryNodeName"`
	Templates     map[string]WorkflowNodeTemplate `json:"templates"`
}

type WorkflowNodeTemplate struct {
	Name         string                        `json:"name"`
	Type         constant.WorkflowTemplateType `json:"templateType"`
	Children     []string                      `json:"children,omitempty"`
	*EmbedAction `json:",inline"`
}

type EmbedAction struct {
	PodShutdown *PodShutdownAction `json:"podShutdown,omitempty"`
}

type PodShutdownAction struct {
	Target chaos.ExperimentTarget `json:"target"`
}

func (w *Workflow) IsRunning() bool {
	return w.Status == chaos.ExperimentStatus_EXPERIMENT_STATUS_RUNNING
}

func (w *Workflow) SetStatusRunning(now time.Time) {
	w.Draft = false
	w.Status = chaos.ExperimentStatus_EXPERIMENT_STATUS_RUNNING
	w.StartedAt = &now
}

func (w *Workflow) SetStatusDeleted(now time.Time) {
	w.Status = chaos.ExperimentStatus_EXPERIMENT_STATUS_DELETED
	w.DeletedAt = &now
	for _, node := range w.Nodes {
		if node.IsRunning() {
			node.SetStatusFailed(now, "workflow is deleted")
		}
	}
}

func (w *Workflow) SetStatusSuccess(now time.Time) {
	w.Status = chaos.ExperimentStatus_EXPERIMENT_STATUS_SUCCESS
	w.CompletedAt = &now
}

func (w *Workflow) SetStatusFailed(now time.Time, message string) {
	w.Status = chaos.ExperimentStatus_EXPERIMENT_STATUS_FAILED
	w.Message = message
	w.CompletedAt = &now
}

func (w *Workflow) SetStatusFailedAndPropagateToAllNodes(now time.Time, message string) {
	w.SetStatusFailed(now, message)
	for _, node := range w.Nodes {
		if node.IsRunning() {
			node.SetStatusFailed(now, message)
		}
	}
}

func (w *Workflow) SetSummary(summary string) {
	w.Summary = summary
}

func (w *Workflow) SetReportLink(link string) {
	w.ReportLink = link
}
