package cmd

import (
	"context"
	"encoding/json"
	"os"
	"testing"

	"github.com/urfave/cli/v3"
)

// TestWorkflowCommandStructure tests that the workflow command is properly structured
func TestWorkflowCommandStructure(t *testing.T) {
	cmd := WorkflowCommand()

	if cmd.Name != "workflow" {
		t.Errorf("Expected command name 'workflow', got '%s'", cmd.Name)
	}

	if cmd.Usage == "" {
		t.Error("Command usage should not be empty")
	}

	// Check subcommands exist
	expectedSubcmds := []string{"template", "instance", "node"}
	subcmdMap := make(map[string]bool)
	for _, subcmd := range cmd.Commands {
		subcmdMap[subcmd.Name] = true
	}

	for _, expected := range expectedSubcmds {
		if !subcmdMap[expected] {
			t.Errorf("Missing expected subcommand: %s", expected)
		}
	}
}

// TestWorkflowTemplateSubcommands tests the template subcommand structure
func TestWorkflowTemplateSubcommands(t *testing.T) {
	cmd := WorkflowCommand()

	var templateCmd *cli.Command
	for _, c := range cmd.Commands {
		if c.Name == "template" {
			templateCmd = c
			break
		}
	}

	if templateCmd == nil {
		t.Fatal("template subcommand not found")
	}

	expectedActions := []string{"list", "get", "create", "update", "delete"}
	actionMap := make(map[string]bool)
	for _, action := range templateCmd.Commands {
		actionMap[action.Name] = true
	}

	for _, expected := range expectedActions {
		if !actionMap[expected] {
			t.Errorf("Missing template action: %s", expected)
		}
	}
}

// TestWorkflowInstanceSubcommands tests the instance subcommand structure
func TestWorkflowInstanceSubcommands(t *testing.T) {
	cmd := WorkflowCommand()

	var instanceCmd *cli.Command
	for _, c := range cmd.Commands {
		if c.Name == "instance" {
			instanceCmd = c
			break
		}
	}

	if instanceCmd == nil {
		t.Fatal("instance subcommand not found")
	}

	expectedActions := []string{"list", "get", "start", "cancel"}
	actionMap := make(map[string]bool)
	for _, action := range instanceCmd.Commands {
		actionMap[action.Name] = true
	}

	for _, expected := range expectedActions {
		if !actionMap[expected] {
			t.Errorf("Missing instance action: %s", expected)
		}
	}
}

// TestWorkflowNodeSubcommands tests the node subcommand structure
func TestWorkflowNodeSubcommands(t *testing.T) {
	cmd := WorkflowCommand()

	var nodeCmd *cli.Command
	for _, c := range cmd.Commands {
		if c.Name == "node" {
			nodeCmd = c
			break
		}
	}

	if nodeCmd == nil {
		t.Fatal("node subcommand not found")
	}

	expectedActions := []string{"list", "get", "retry"}
	actionMap := make(map[string]bool)
	for _, action := range nodeCmd.Commands {
		actionMap[action.Name] = true
	}

	for _, expected := range expectedActions {
		if !actionMap[expected] {
			t.Errorf("Missing node action: %s", expected)
		}
	}
}

// TestWorkflowTemplateFlags tests that template command flags are properly defined
func TestWorkflowTemplateFlags(t *testing.T) {
	cmd := WorkflowCommand()

	var templateCmd *cli.Command
	for _, c := range cmd.Commands {
		if c.Name == "template" {
			templateCmd = c
			break
		}
	}

	// Test create command flags
	var createCmd *cli.Command
	for _, c := range templateCmd.Commands {
		if c.Name == "create" {
			createCmd = c
			break
		}
	}

	flagNames := make(map[string]bool)
	for _, flag := range createCmd.Flags {
		flagNames[flag.Names()[0]] = true
	}

	expectedFlags := []string{"name", "description", "definition", "active"}
	for _, expected := range expectedFlags {
		if !flagNames[expected] {
			t.Errorf("Missing create flag: %s", expected)
		}
	}

	// Test that id flag is required for get command
	var getCmd *cli.Command
	for _, c := range templateCmd.Commands {
		if c.Name == "get" {
			getCmd = c
			break
		}
	}

	var idFlag *cli.StringFlag
	for _, flag := range getCmd.Flags {
		if flag.Names()[0] == "id" {
			idFlag = flag.(*cli.StringFlag)
			break
		}
	}

	if idFlag == nil {
		t.Error("Missing id flag on get command")
	} else if !idFlag.Required {
		t.Error("id flag should be required on get command")
	}
}

// TestWorkflowInstanceFlags tests that instance command flags are properly defined
func TestWorkflowInstanceFlags(t *testing.T) {
	cmd := WorkflowCommand()

	var instanceCmd *cli.Command
	for _, c := range cmd.Commands {
		if c.Name == "instance" {
			instanceCmd = c
			break
		}
	}

	// Test start command flags
	var startCmd *cli.Command
	for _, c := range instanceCmd.Commands {
		if c.Name == "start" {
			startCmd = c
			break
		}
	}

	flagNames := make(map[string]bool)
	for _, flag := range startCmd.Flags {
		flagNames[flag.Names()[0]] = true
	}

	expectedFlags := []string{"template", "service", "context"}
	for _, expected := range expectedFlags {
		if !flagNames[expected] {
			t.Errorf("Missing start flag: %s", expected)
		}
	}

	// Test that template flag is required
	var templateFlag *cli.StringFlag
	for _, flag := range startCmd.Flags {
		if flag.Names()[0] == "template" {
			templateFlag = flag.(*cli.StringFlag)
			break
		}
	}

	if templateFlag == nil {
		t.Error("Missing template flag on start command")
	} else if !templateFlag.Required {
		t.Error("template flag should be required on start command")
	}
}

// TestWorkflowNodeFlags tests that node command flags are properly defined
func TestWorkflowNodeFlags(t *testing.T) {
	cmd := WorkflowCommand()

	var nodeCmd *cli.Command
	for _, c := range cmd.Commands {
		if c.Name == "node" {
			nodeCmd = c
			break
		}
	}

	// Test list command flags
	var listCmd *cli.Command
	for _, c := range nodeCmd.Commands {
		if c.Name == "list" {
			listCmd = c
			break
		}
	}

	var instanceFlag *cli.StringFlag
	for _, flag := range listCmd.Flags {
		if flag.Names()[0] == "instance" {
			instanceFlag = flag.(*cli.StringFlag)
			break
		}
	}

	if instanceFlag == nil {
		t.Error("Missing instance flag on node list command")
	} else if !instanceFlag.Required {
		t.Error("instance flag should be required on node list command")
	}
}

// TestReadFileOrString tests the helper function for reading files
func TestReadFileOrString(t *testing.T) {
	// Test with regular string (no @ prefix)
	input := "hello world"
	result := ReadFileOrString(input)
	if result != input {
		t.Errorf("Expected '%s', got '%s'", input, result)
	}

	// Test with non-existent file (should return original)
	input = "@nonexistent_file.json"
	result = ReadFileOrString(input)
	if result != input {
		t.Errorf("Expected original input for non-existent file, got '%s'", result)
	}

	// Test with actual file
	tmpFile, err := os.CreateTemp("", "test_*.json")
	if err != nil {
		t.Fatalf("Failed to create temp file: %v", err)
	}
	defer os.Remove(tmpFile.Name())

	testContent := `{"test": "content"}`
	if _, err := tmpFile.WriteString(testContent); err != nil {
		t.Fatalf("Failed to write to temp file: %v", err)
	}
	tmpFile.Close()

	result = ReadFileOrString("@" + tmpFile.Name())
	if result != testContent {
		t.Errorf("Expected file content '%s', got '%s'", testContent, result)
	}
}

// TestWorkflowTemplateJSON tests JSON marshaling of WorkflowTemplate
func TestWorkflowTemplateJSON(t *testing.T) {
	template := WorkflowTemplate{
		ID:          "1",
		Name:        "Test Template",
		Description: "A test template",
		Definition:  `{"nodes": []}`,
		IsActive:    true,
		CreatedBy:   &User{ID: "1", Email: "test@example.com"},
		CreatedAt:   "2024-01-01T00:00:00Z",
		UpdatedAt:   "2024-01-01T00:00:00Z",
	}

	data, err := json.Marshal(template)
	if err != nil {
		t.Fatalf("Failed to marshal WorkflowTemplate: %v", err)
	}

	var unmarshaled WorkflowTemplate
	if err := json.Unmarshal(data, &unmarshaled); err != nil {
		t.Fatalf("Failed to unmarshal WorkflowTemplate: %v", err)
	}

	if unmarshaled.ID != template.ID {
		t.Errorf("Expected ID '%s', got '%s'", template.ID, unmarshaled.ID)
	}
	if unmarshaled.Name != template.Name {
		t.Errorf("Expected Name '%s', got '%s'", template.Name, unmarshaled.Name)
	}
	if unmarshaled.IsActive != template.IsActive {
		t.Errorf("Expected IsActive %v, got %v", template.IsActive, unmarshaled.IsActive)
	}
}

// TestWorkflowInstanceJSON tests JSON marshaling of WorkflowInstance
func TestWorkflowInstanceJSON(t *testing.T) {
	completedAt := "2024-01-02T00:00:00Z"
	instance := WorkflowInstance{
		ID:          "1",
		Template:    &WorkflowTemplate{ID: "1", Name: "Test"},
		Status:      "running",
		Context:     `{"key": "value"}`,
		Service:     &Service{ID: "1", Name: "Test Service"},
		CreatedAt:   "2024-01-01T00:00:00Z",
		UpdatedAt:   "2024-01-01T00:00:00Z",
		CompletedAt: &completedAt,
	}

	data, err := json.Marshal(instance)
	if err != nil {
		t.Fatalf("Failed to marshal WorkflowInstance: %v", err)
	}

	var unmarshaled WorkflowInstance
	if err := json.Unmarshal(data, &unmarshaled); err != nil {
		t.Fatalf("Failed to unmarshal WorkflowInstance: %v", err)
	}

	if unmarshaled.ID != instance.ID {
		t.Errorf("Expected ID '%s', got '%s'", instance.ID, unmarshaled.ID)
	}
	if unmarshaled.Status != instance.Status {
		t.Errorf("Expected Status '%s', got '%s'", instance.Status, unmarshaled.Status)
	}
	if unmarshaled.CompletedAt == nil || *unmarshaled.CompletedAt != completedAt {
		t.Errorf("Expected CompletedAt '%s', got '%v'", completedAt, unmarshaled.CompletedAt)
	}
}

// TestWorkflowNodeJSON tests JSON marshaling of WorkflowNode
func TestWorkflowNodeJSON(t *testing.T) {
	startedAt := "2024-01-01T01:00:00Z"
	node := WorkflowNode{
		ID:          "1",
		NodeKey:     "node_1",
		NodeType:    "task",
		Status:      "running",
		Task:        &Task{ID: "1", Title: "Test Task"},
		InputData:   `{"input": "data"}`,
		OutputData:  `{"output": "data"}`,
		RetryCount:  2,
		CreatedAt:   "2024-01-01T00:00:00Z",
		UpdatedAt:   "2024-01-01T00:00:00Z",
		StartedAt:   &startedAt,
		CompletedAt: nil,
	}

	data, err := json.Marshal(node)
	if err != nil {
		t.Fatalf("Failed to marshal WorkflowNode: %v", err)
	}

	var unmarshaled WorkflowNode
	if err := json.Unmarshal(data, &unmarshaled); err != nil {
		t.Fatalf("Failed to unmarshal WorkflowNode: %v", err)
	}

	if unmarshaled.ID != node.ID {
		t.Errorf("Expected ID '%s', got '%s'", node.ID, unmarshaled.ID)
	}
	if unmarshaled.NodeKey != node.NodeKey {
		t.Errorf("Expected NodeKey '%s', got '%s'", node.NodeKey, unmarshaled.NodeKey)
	}
	if unmarshaled.RetryCount != node.RetryCount {
		t.Errorf("Expected RetryCount %d, got %d", node.RetryCount, unmarshaled.RetryCount)
	}
}

// TestWorkflowTemplateListJSONFlag tests the JSON flag on template list
func TestWorkflowTemplateListJSONFlag(t *testing.T) {
	cmd := WorkflowCommand()

	var templateCmd *cli.Command
	for _, c := range cmd.Commands {
		if c.Name == "template" {
			templateCmd = c
			break
		}
	}

	var listCmd *cli.Command
	for _, c := range templateCmd.Commands {
		if c.Name == "list" {
			listCmd = c
			break
		}
	}

	var jsonFlag *cli.BoolFlag
	for _, flag := range listCmd.Flags {
		if flag.Names()[0] == "json" {
			jsonFlag = flag.(*cli.BoolFlag)
			break
		}
	}

	if jsonFlag == nil {
		t.Error("Missing json flag on template list command")
	}
}

// TestWorkflowCommandInRoot tests that WorkflowCommand is registered in RootCommand
func TestWorkflowCommandInRoot(t *testing.T) {
	rootCmd := RootCommand()

	found := false
	for _, cmd := range rootCmd.Commands {
		if cmd.Name == "workflow" {
			found = true
			break
		}
	}

	if !found {
		t.Error("WorkflowCommand not found in RootCommand")
	}
}

// TestWorkflowCommandHelp tests that help text is available
func TestWorkflowCommandHelp(t *testing.T) {
	cmd := WorkflowCommand()

	if cmd.Description == "" {
		t.Error("WorkflowCommand should have a description")
	}

	// Test that subcommands have descriptions
	for _, subcmd := range cmd.Commands {
		if subcmd.Usage == "" {
			t.Errorf("Subcommand '%s' should have usage text", subcmd.Name)
		}
	}
}

// BenchmarkWorkflowCommand benchmarks the command creation
func BenchmarkWorkflowCommand(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = WorkflowCommand()
	}
}

// TestWorkflowTemplateRequiredFlags tests that required flags are enforced
func TestWorkflowTemplateRequiredFlags(t *testing.T) {
	tests := []struct {
		name       string
		action     string
		shouldHave []string
	}{
		{"get requires id", "get", []string{"id"}},
		{"delete requires id", "delete", []string{"id"}},
		{"update requires id", "update", []string{"id"}},
	}

	cmd := WorkflowCommand()

	var templateCmd *cli.Command
	for _, c := range cmd.Commands {
		if c.Name == "template" {
			templateCmd = c
			break
		}
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			var actionCmd *cli.Command
			for _, c := range templateCmd.Commands {
				if c.Name == tt.action {
					actionCmd = c
					break
				}
			}

			if actionCmd == nil {
				t.Fatalf("Action '%s' not found", tt.action)
			}

			for _, requiredFlag := range tt.shouldHave {
				found := false
				for _, flag := range actionCmd.Flags {
					if flag.Names()[0] == requiredFlag {
						if strFlag, ok := flag.(*cli.StringFlag); ok {
							if strFlag.Required {
								found = true
							}
						}
						break
					}
				}
				if !found {
					t.Errorf("Flag '%s' should be required for action '%s'", requiredFlag, tt.action)
				}
			}
		})
	}
}

// TestWorkflowInstanceRequiredFlags tests that required flags are enforced
func TestWorkflowInstanceRequiredFlags(t *testing.T) {
	tests := []struct {
		name       string
		action     string
		shouldHave []string
	}{
		{"get requires id", "get", []string{"id"}},
		{"start requires template", "start", []string{"template"}},
		{"cancel requires id", "cancel", []string{"id"}},
	}

	cmd := WorkflowCommand()

	var instanceCmd *cli.Command
	for _, c := range cmd.Commands {
		if c.Name == "instance" {
			instanceCmd = c
			break
		}
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			var actionCmd *cli.Command
			for _, c := range instanceCmd.Commands {
				if c.Name == tt.action {
					actionCmd = c
					break
				}
			}

			if actionCmd == nil {
				t.Fatalf("Action '%s' not found", tt.action)
			}

			for _, requiredFlag := range tt.shouldHave {
				found := false
				for _, flag := range actionCmd.Flags {
					if flag.Names()[0] == requiredFlag {
						if strFlag, ok := flag.(*cli.StringFlag); ok {
							if strFlag.Required {
								found = true
							}
						}
						break
					}
				}
				if !found {
					t.Errorf("Flag '%s' should be required for action '%s'", requiredFlag, tt.action)
				}
			}
		})
	}
}

// TestWorkflowNodeRequiredFlags tests that required flags are enforced
func TestWorkflowNodeRequiredFlags(t *testing.T) {
	tests := []struct {
		name       string
		action     string
		shouldHave []string
	}{
		{"list requires instance", "list", []string{"instance"}},
		{"get requires id", "get", []string{"id"}},
		{"retry requires id", "retry", []string{"id"}},
	}

	cmd := WorkflowCommand()

	var nodeCmd *cli.Command
	for _, c := range cmd.Commands {
		if c.Name == "node" {
			nodeCmd = c
			break
		}
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			var actionCmd *cli.Command
			for _, c := range nodeCmd.Commands {
				if c.Name == tt.action {
					actionCmd = c
					break
				}
			}

			if actionCmd == nil {
				t.Fatalf("Action '%s' not found", tt.action)
			}

			for _, requiredFlag := range tt.shouldHave {
				found := false
				for _, flag := range actionCmd.Flags {
					if flag.Names()[0] == requiredFlag {
						if strFlag, ok := flag.(*cli.StringFlag); ok {
							if strFlag.Required {
								found = true
							}
						}
						break
					}
				}
				if !found {
					t.Errorf("Flag '%s' should be required for action '%s'", requiredFlag, tt.action)
				}
			}
		})
	}
}

// Mock context for testing command actions
var _ = context.Background()
