package domain

import (
	"errors"
	"testing"
)

func TestAgentProvider_IsValid(t *testing.T) {
	tests := []struct {
		provider AgentProvider
		want     bool
	}{
		{AgentProviderClaudeCode, true},
		{AgentProviderOpenCode, true},
		{"unknown", false},
		{"", false},
	}

	for _, tt := range tests {
		t.Run(string(tt.provider), func(t *testing.T) {
			if got := tt.provider.IsValid(); got != tt.want {
				t.Errorf("IsValid() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestAgentProvider_String(t *testing.T) {
	if got := AgentProviderClaudeCode.String(); got != "claudecode" {
		t.Errorf("String() = %q, want %q", got, "claudecode")
	}
	if got := AgentProviderOpenCode.String(); got != "opencode" {
		t.Errorf("String() = %q, want %q", got, "opencode")
	}
}

func TestParseAgentProvider(t *testing.T) {
	tests := []struct {
		input   string
		want    AgentProvider
		wantErr bool
	}{
		{"claudecode", AgentProviderClaudeCode, false},
		{"opencode", AgentProviderOpenCode, false},
		{"unknown", "", true},
		{"", "", true},
		{"CLAUDECODE", "", true}, // case sensitive
	}

	for _, tt := range tests {
		t.Run(tt.input, func(t *testing.T) {
			got, err := ParseAgentProvider(tt.input)
			if (err != nil) != tt.wantErr {
				t.Errorf("ParseAgentProvider() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if got != tt.want {
				t.Errorf("ParseAgentProvider() = %v, want %v", got, tt.want)
			}
			if tt.wantErr && !errors.Is(err, ErrInvalidAgentProvider) {
				t.Errorf("expected ErrInvalidAgentProvider, got %v", err)
			}
		})
	}
}

func TestValidAgentProviders(t *testing.T) {
	providers := ValidAgentProviders()
	if len(providers) != 2 {
		t.Errorf("expected 2 providers, got %d", len(providers))
	}

	found := make(map[AgentProvider]bool)
	for _, p := range providers {
		found[p] = true
	}

	if !found[AgentProviderClaudeCode] {
		t.Error("expected claudecode in valid providers")
	}
	if !found[AgentProviderOpenCode] {
		t.Error("expected opencode in valid providers")
	}
}

func TestAgentRequest_Validate(t *testing.T) {
	tests := []struct {
		name    string
		request AgentRequest
		wantErr error
	}{
		{
			name:    "valid request",
			request: AgentRequest{Prompt: "Hello"},
			wantErr: nil,
		},
		{
			name:    "empty prompt",
			request: AgentRequest{Prompt: ""},
			wantErr: ErrPromptRequired,
		},
		{
			name:    "negative timeout",
			request: AgentRequest{Prompt: "Hello", Timeout: -1},
			wantErr: ErrInvalidTimeout,
		},
		{
			name:    "zero timeout is valid",
			request: AgentRequest{Prompt: "Hello", Timeout: 0},
			wantErr: nil,
		},
		{
			name:    "positive timeout is valid",
			request: AgentRequest{Prompt: "Hello", Timeout: 5},
			wantErr: nil,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.request.Validate()
			if tt.wantErr != nil {
				if !errors.Is(err, tt.wantErr) {
					t.Errorf("Validate() error = %v, want %v", err, tt.wantErr)
				}
			} else if err != nil {
				t.Errorf("Validate() unexpected error = %v", err)
			}
		})
	}
}

func TestAgentResult_Success(t *testing.T) {
	tests := []struct {
		name     string
		result   AgentResult
		expected bool
	}{
		{
			name:     "success with zero exit code",
			result:   AgentResult{ExitCode: 0, Error: nil},
			expected: true,
		},
		{
			name:     "failure with non-zero exit code",
			result:   AgentResult{ExitCode: 1, Error: nil},
			expected: false,
		},
		{
			name:     "failure with error",
			result:   AgentResult{ExitCode: 0, Error: errors.New("test error")},
			expected: false,
		},
		{
			name:     "failure with both error and exit code",
			result:   AgentResult{ExitCode: 1, Error: errors.New("test error")},
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := tt.result.Success(); got != tt.expected {
				t.Errorf("Success() = %v, want %v", got, tt.expected)
			}
		})
	}
}
