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
)

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

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                int64      `json:"state,omitempty" bson:"state,omitempty"`                                       // 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 = int64(SUCCESS.EnumIndex())
	case "pending": // Pending
		wfa.State = int64(SCHEDULED.EnumIndex())
	case "running": // Running
		wfa.State = int64(STARTED.EnumIndex())
	default: // Failed
		wfa.State = int64(FAILURE.EnumIndex())
	}
	return wfa
}

func (ao *WorkflowExecution) GetID() string {
	return ao.UUID
}

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

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

func (d *WorkflowExecution) GetAccessor(caller *tools.HTTPCaller) utils.Accessor {
	data := New()                               // Create a new instance of the accessor
	data.Init(tools.WORKFLOW_EXECUTION, caller) // Initialize the accessor with the WORKFLOW_EXECUTION model type
	return data
}

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

// Serialize returns the WorkflowExecution as a map
func (dma *WorkflowExecution) 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
}
