package workflow_execution

import (
	"encoding/json"
	"strings"
	"time"

	"cloud.o-forge.io/core/oc-lib/models/utils"
	"cloud.o-forge.io/core/oc-lib/tools"
	"github.com/google/uuid"
)

// ScheduledType - Enum for the different states of a workflow execution
type ScheduledType int

const (
	SCHEDULED ScheduledType = iota + 1
	STARTED
	FAILURE
	SUCCESS
	FORGOTTEN
)

var str = [...]string{
	"scheduled",
	"started",
	"failure",
	"success",
	"forgotten",
}

func FromInt(i int) string {
	return str[i]
}

func (d ScheduledType) String() string {
	return str[d]
}

// EnumIndex - Creating common behavior - give the type a EnumIndex functio
func (d ScheduledType) EnumIndex() int {
	return int(d)
}

/*
* WorkflowExecutions is a struct that represents a list of workflow executions
* Warning: No user can write (del, post, put) a workflow execution, it is only used by the system
* workflows generate their own executions
 */
type WorkflowExecutions struct {
	WorkflowID string               `json:"workflow_id" bson:"workflow_id"`
	ResourceID string               `json:"resource_id" bson:"resource_id"`
	Executions []*WorkflowExecution `json:"executions" bson:"executions"`
}

// New - Creates a new instance of the WorkflowExecutions from a map
func (dma *WorkflowExecutions) Deserialize(j map[string]interface{}) *WorkflowExecutions {
	b, err := json.Marshal(j)
	if err != nil {
		return nil
	}
	json.Unmarshal(b, dma)
	return dma
}

// Serialize - Returns the WorkflowExecutions as a map
func (dma *WorkflowExecutions) Serialize() map[string]interface{} {
	var m map[string]interface{}
	b, err := json.Marshal(dma)
	if err != nil {
		return nil
	}
	json.Unmarshal(b, &m)
	return m
}

/*
* WorkflowExecution is a struct that represents a workflow execution
* Warning: No user can write (del, post, put)  a workflow execution, it is only used by the system
* workflows generate their own executions
 */
type WorkflowExecution struct {
	utils.AbstractObject               // AbstractObject contains the basic fields of an object (id, name)
	ExecDate             *time.Time    `json:"execution_date,omitempty" bson:"execution_date,omitempty" validate:"required"` // ExecDate is the execution date of the workflow, is required
	EndDate              *time.Time    `json:"end_date,omitempty" bson:"end_date,omitempty"`                                 // EndDate is the end date of the workflow
	State                ScheduledType `json:"state" bson:"state" default:"0"`                                               // State is the state of the workflow
	WorkflowID           string        `json:"workflow_id" bson:"workflow_id,omitempty"`                                     // WorkflowID is the ID of the workflow
}

func (wfa *WorkflowExecution) Equals(we *WorkflowExecution) bool {
	return wfa.ExecDate.Equal(*we.ExecDate) && wfa.WorkflowID == we.WorkflowID
}

// tool to transform the argo status to a state
func (wfa *WorkflowExecution) ArgoStatusToState(status string) *WorkflowExecution {
	status = strings.ToLower(status)
	switch status {
	case "succeeded": // Succeeded
		wfa.State = SUCCESS
	case "pending": // Pending
		wfa.State = SCHEDULED
	case "running": // Running
		wfa.State = STARTED
	default: // Failed
		wfa.State = FAILURE
	}
	return wfa
}

func (r *WorkflowExecution) GenerateID() {
	r.UUID = uuid.New().String()
}

func (d *WorkflowExecution) GetName() string {
	return d.UUID + "_" + d.ExecDate.String()
}

func (d *WorkflowExecution) GetAccessor(peerID string, groups []string, caller *tools.HTTPCaller) utils.Accessor {
	return New(tools.WORKFLOW_EXECUTION, peerID, groups, caller) // Create a new instance of the accessor
}
