package tests

import (
	"context"
	"fmt"
	"testing"

	"github.com/rockliang/poimen/workflows/internal/routing"
	"github.com/rockliang/poimen/workflows/statemachine"
	"github.com/stretchr/testify/require"
	"go.temporal.io/sdk/testsuite"
)

func TestRoutingWorkflow_SimpleWorkflow(t *testing.T) {
	testSuite := &testsuite.WorkflowTestSuite{}
	env := testSuite.NewTestWorkflowEnvironment()

	// Register mock activity
	env.RegisterActivity(mockCloneRepoActivity)

	// Create simple workflow spec
	spec := &routing.WorkflowSpec{
		Name: "test-workflow",
		Input: map[string]interface{}{
			"repo":   "https://github.com/test/repo",
			"branch": "main",
		},
		States: []routing.State{
			{
				Name:     "Clone",
				Type:     routing.StateTypeTask,
				Resource: "mockCloneRepoActivity",
				Parameters: map[string]interface{}{
					"repo":   "${input.repo}",
					"branch": "${input.branch}",
				},
				Timeout: "5m",
				Retry: &routing.RetryPolicy{
					MaxAttempts:     2,
					BackoffRate:     1.5,
					InitialInterval: "1s",
				},
				End: true,
			},
		},
	}

	input := statemachine.RoutingWorkflowInput{Spec: spec}

	env.ExecuteWorkflow(statemachine.RoutingWorkflow, input)

	require.True(t, env.IsWorkflowCompleted())
	require.NoError(t, env.GetWorkflowError())

	var output statemachine.RoutingWorkflowOutput
	require.NoError(t, env.GetWorkflowResult(&output))
	require.Equal(t, "COMPLETED", output.Status)
	require.NotNil(t, output.FinalOutput)
}

func TestRoutingWorkflow_MultiStepWorkflow(t *testing.T) {
	testSuite := &testsuite.WorkflowTestSuite{}
	env := testSuite.NewTestWorkflowEnvironment()

	// Register mock activities
	env.RegisterActivity(mockCloneRepoActivity)
	env.RegisterActivity(mockAnalyzeActivity)

	// Create multi-step workflow spec
	spec := &routing.WorkflowSpec{
		Name: "multi-step-workflow",
		Input: map[string]interface{}{
			"repo": "https://github.com/test/repo",
		},
		States: []routing.State{
			{
				Name:     "Clone",
				Type:     routing.StateTypeTask,
				Resource: "mockCloneRepoActivity",
				Parameters: map[string]interface{}{
					"repo": "${input.repo}",
				},
				Timeout: "5m",
				Next:    "Analyze",
			},
			{
				Name:     "Analyze",
				Type:     routing.StateTypeTask,
				Resource: "mockAnalyzeActivity",
				Parameters: map[string]interface{}{
					"path": "${Clone.output.path}",
				},
				Timeout: "10m",
				End:     true,
			},
		},
	}

	input := statemachine.RoutingWorkflowInput{Spec: spec}

	env.ExecuteWorkflow(statemachine.RoutingWorkflow, input)

	require.True(t, env.IsWorkflowCompleted())
	require.NoError(t, env.GetWorkflowError())

	var output statemachine.RoutingWorkflowOutput
	require.NoError(t, env.GetWorkflowResult(&output))
	t.Logf("Output: %+v", output)
	t.Logf("Error: %s", output.Error)
	require.Equal(t, "COMPLETED", output.Status)
	require.Contains(t, output.StepResults, "Clone")
	require.Contains(t, output.StepResults, "Analyze")
}

func TestRoutingWorkflow_PassState(t *testing.T) {
	testSuite := &testsuite.WorkflowTestSuite{}
	env := testSuite.NewTestWorkflowEnvironment()

	// Create workflow with Pass state
	spec := &routing.WorkflowSpec{
		Name:  "pass-state-workflow",
		Input: map[string]interface{}{},
		States: []routing.State{
			{
				Name:   "StaticResult",
				Type:   routing.StateTypePass,
				Result: map[string]interface{}{"status": "ok", "message": "static result"},
				End:    true,
			},
		},
	}

	input := statemachine.RoutingWorkflowInput{Spec: spec}

	env.ExecuteWorkflow(statemachine.RoutingWorkflow, input)

	require.True(t, env.IsWorkflowCompleted())
	require.NoError(t, env.GetWorkflowError())

	var output statemachine.RoutingWorkflowOutput
	require.NoError(t, env.GetWorkflowResult(&output))
	require.Equal(t, "COMPLETED", output.Status)
}

func TestRoutingWorkflow_FailState(t *testing.T) {
	testSuite := &testsuite.WorkflowTestSuite{}
	env := testSuite.NewTestWorkflowEnvironment()

	// Create workflow with Fail state
	spec := &routing.WorkflowSpec{
		Name:  "fail-state-workflow",
		Input: map[string]interface{}{},
		States: []routing.State{
			{
				Name:  "HandleError",
				Type:  routing.StateTypeFail,
				Error: "WorkflowError",
				Cause: "Something went wrong",
			},
		},
	}

	input := statemachine.RoutingWorkflowInput{Spec: spec}

	env.ExecuteWorkflow(statemachine.RoutingWorkflow, input)

	require.True(t, env.IsWorkflowCompleted())
	require.NoError(t, env.GetWorkflowError())

	var output statemachine.RoutingWorkflowOutput
	require.NoError(t, env.GetWorkflowResult(&output))
	require.Equal(t, "FAILED", output.Status)
	require.Contains(t, output.Error, "WorkflowError")
}

func TestRoutingWorkflow_ErrorCatch(t *testing.T) {
	testSuite := &testsuite.WorkflowTestSuite{}
	env := testSuite.NewTestWorkflowEnvironment()

	// Register mock activities
	env.RegisterActivity(mockFailingActivity)

	// Create workflow with error handling
	spec := &routing.WorkflowSpec{
		Name:  "error-catch-workflow",
		Input: map[string]interface{}{},
		States: []routing.State{
			{
				Name:       "FlakyStep",
				Type:       routing.StateTypeTask,
				Resource:   "mockFailingActivity",
				Parameters: map[string]interface{}{},
				Timeout:    "1m",
				Retry: &routing.RetryPolicy{
					MaxAttempts:     1,
					BackoffRate:     1.0,
					InitialInterval: "1s",
				},
				Catch: []routing.CatchClause{
					{
						ErrorEquals: []string{"ActivityError"},
						Next:        "HandleError",
					},
				},
				Next: "Success",
			},
			{
				Name:   "Success",
				Type:   routing.StateTypePass,
				Result: "success",
				End:    true,
			},
			{
				Name:  "HandleError",
				Type:  routing.StateTypeFail,
				Error: "CaughtError",
				Cause: "Activity failed and was caught",
			},
		},
	}

	input := statemachine.RoutingWorkflowInput{Spec: spec}

	env.ExecuteWorkflow(statemachine.RoutingWorkflow, input)

	require.True(t, env.IsWorkflowCompleted())
	require.NoError(t, env.GetWorkflowError())

	var output statemachine.RoutingWorkflowOutput
	require.NoError(t, env.GetWorkflowResult(&output))
	require.Equal(t, "FAILED", output.Status)
	require.Contains(t, output.Error, "CaughtError")
}

func TestRoutingWorkflow_EmptySpec(t *testing.T) {
	testSuite := &testsuite.WorkflowTestSuite{}
	env := testSuite.NewTestWorkflowEnvironment()

	// Empty spec
	input := statemachine.RoutingWorkflowInput{Spec: nil}

	env.ExecuteWorkflow(statemachine.RoutingWorkflow, input)

	require.True(t, env.IsWorkflowCompleted())
	require.NoError(t, env.GetWorkflowError())

	var output statemachine.RoutingWorkflowOutput
	require.NoError(t, env.GetWorkflowResult(&output))
	require.Equal(t, "FAILED", output.Status)
	require.Contains(t, output.Error, "empty")
}

// Mock activities
func mockCloneRepoActivity(ctx context.Context, params map[string]interface{}) (map[string]interface{}, error) {
	return map[string]interface{}{
		"path":   "/tmp/cloned-repo",
		"commit": "abc123",
		"branch": "main",
	}, nil
}

func mockAnalyzeActivity(ctx context.Context, params map[string]interface{}) (map[string]interface{}, error) {
	return map[string]interface{}{
		"quality": 0.85,
		"issues":  []string{},
		"summary": "Code analysis complete",
	}, nil
}

func mockFailingActivity(ctx context.Context, params map[string]interface{}) (map[string]interface{}, error) {
	return nil, fmt.Errorf("mock activity failure")
}
