package workflow_execution_test

import (
	"testing"
	"time"

	"cloud.o-forge.io/core/oc-lib/models/common/enum"
	"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
	"cloud.o-forge.io/core/oc-lib/tools"
	"github.com/stretchr/testify/assert"
)

// ---- WorkflowExecution model ----

func TestWorkflowExecution_StoreDraftDefault(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	we.StoreDraftDefault()
	assert.False(t, we.IsDraft)
	assert.Equal(t, enum.SCHEDULED, we.State)
}

func TestWorkflowExecution_CanDelete_Draft(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	we.IsDraft = true
	assert.True(t, we.CanDelete())
}

func TestWorkflowExecution_CanDelete_NonDraft(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	we.IsDraft = false
	assert.False(t, we.CanDelete())
}

func TestWorkflowExecution_CanUpdate_StateChange(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{State: enum.SCHEDULED}
	set := &workflow_execution.WorkflowExecution{State: enum.STARTED}
	ok, returned := we.CanUpdate(set)
	assert.True(t, ok)
	// Only the state should be propagated
	assert.Equal(t, enum.STARTED, returned.(*workflow_execution.WorkflowExecution).State)
}

func TestWorkflowExecution_CanUpdate_SameState_NonDraft(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{State: enum.SCHEDULED}
	we.IsDraft = false
	set := &workflow_execution.WorkflowExecution{State: enum.SCHEDULED}
	ok, _ := we.CanUpdate(set)
	// !r.IsDraft == true → ok
	assert.True(t, ok)
}

func TestWorkflowExecution_CanUpdate_SameState_Draft(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{State: enum.SCHEDULED}
	we.IsDraft = true
	set := &workflow_execution.WorkflowExecution{State: enum.SCHEDULED}
	ok, _ := we.CanUpdate(set)
	// !r.IsDraft == false (it is draft) → ok false
	assert.False(t, ok)
}

func TestWorkflowExecution_Equals_True(t *testing.T) {
	now := time.Now()
	a := &workflow_execution.WorkflowExecution{WorkflowID: "wf-1"}
	a.ExecDate = now
	b := &workflow_execution.WorkflowExecution{WorkflowID: "wf-1"}
	b.ExecDate = now
	assert.True(t, a.Equals(b))
}

func TestWorkflowExecution_Equals_DifferentDate(t *testing.T) {
	a := &workflow_execution.WorkflowExecution{WorkflowID: "wf-1"}
	a.ExecDate = time.Now()
	b := &workflow_execution.WorkflowExecution{WorkflowID: "wf-1"}
	b.ExecDate = time.Now().Add(time.Hour)
	assert.False(t, a.Equals(b))
}

func TestWorkflowExecution_Equals_DifferentWorkflow(t *testing.T) {
	now := time.Now()
	a := &workflow_execution.WorkflowExecution{WorkflowID: "wf-1"}
	a.ExecDate = now
	b := &workflow_execution.WorkflowExecution{WorkflowID: "wf-2"}
	b.ExecDate = now
	assert.False(t, a.Equals(b))
}

func TestWorkflowExecution_GetName(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	we.UUID = "exec-uuid"
	we.ExecDate = time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
	name := we.GetName()
	assert.Contains(t, name, "exec-uuid")
	assert.Contains(t, name, "2026")
}

func TestWorkflowExecution_GenerateID(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	we.GenerateID()
	assert.NotEmpty(t, we.UUID)
}

func TestWorkflowExecution_GenerateID_KeepsExisting(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	we.UUID = "existing-uuid"
	we.GenerateID()
	assert.Equal(t, "existing-uuid", we.UUID)
}

func TestWorkflowExecution_VerifyAuth_AlwaysTrue(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	assert.True(t, we.VerifyAuth("get", nil))
	assert.True(t, we.VerifyAuth("delete", &tools.APIRequest{}))
}

func TestWorkflowExecution_GetAccessor(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	acc := we.GetAccessor(&tools.APIRequest{})
	assert.NotNil(t, acc)
}

// ---- ArgoStatusToState ----

func TestArgoStatusToState_Succeeded(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	we.ArgoStatusToState("succeeded")
	assert.Equal(t, enum.SUCCESS, we.State)
}

func TestArgoStatusToState_Pending(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	we.ArgoStatusToState("pending")
	assert.Equal(t, enum.SCHEDULED, we.State)
}

func TestArgoStatusToState_Running(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	we.ArgoStatusToState("running")
	assert.Equal(t, enum.STARTED, we.State)
}

func TestArgoStatusToState_Default_Failed(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	we.ArgoStatusToState("failed")
	assert.Equal(t, enum.FAILURE, we.State)
}

func TestArgoStatusToState_CaseInsensitive(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	we.ArgoStatusToState("SUCCEEDED")
	assert.Equal(t, enum.SUCCESS, we.State)
}

func TestArgoStatusToState_ReturnsPointer(t *testing.T) {
	we := &workflow_execution.WorkflowExecution{}
	result := we.ArgoStatusToState("running")
	assert.Equal(t, we, result)
}

// ---- NewAccessor ----

func TestNewWorkflowExecutionAccessor(t *testing.T) {
	acc := workflow_execution.NewAccessor(&tools.APIRequest{Admin: true})
	assert.NotNil(t, acc)
	assert.Equal(t, tools.WORKFLOW_EXECUTION, acc.GetType())
}

func TestNewWorkflowExecutionAccessor_NilRequest(t *testing.T) {
	acc := workflow_execution.NewAccessor(nil)
	assert.NotNil(t, acc)
	assert.Equal(t, "", acc.GetUser())
	assert.Equal(t, "", acc.GetPeerID())
}
