package authoring

import (
	"testing"

	"github.com/nomadcode/nomadcode-core/internal/projectsync"
	"github.com/nomadcode/nomadcode-core/internal/roadmapsync"
)

func TestDecideAuthoringResult(t *testing.T) {
	intPtr := func(v int) *int { return &v }

	tests := []struct {
		name     string
		input    DecisionInput
		expected Decision
	}{
		{
			name: "bridge failure",
			input: DecisionInput{
				BridgeSuccess: false,
			},
			expected: Decision{
				State:           "failed",
				Reason:          "model bridge response failed",
				FailureCategory: "bridge_failed",
			},
		},
		{
			name: "exit code nonzero",
			input: DecisionInput{
				BridgeSuccess: true,
				ExitCode:      intPtr(1),
			},
			expected: Decision{
				State:           "failed",
				Reason:          "agent process exited with non-zero code 1",
				FailureCategory: "exit_code",
			},
		},
		{
			name: "exit code zero is ignored",
			input: DecisionInput{
				BridgeSuccess: true,
				ExitCode:      intPtr(0),
			},
			expected: Decision{
				State:  "in_progress",
				Reason: "waiting for pushed develop milestone match",
			},
		},
		{
			name: "push failed",
			input: DecisionInput{
				BridgeSuccess: true,
				PushFailed:    true,
			},
			expected: Decision{
				State:           "failed",
				Reason:          "git push to develop branch failed",
				FailureCategory: "push_failed",
			},
		},
		{
			name: "dirty workspace",
			input: DecisionInput{
				BridgeSuccess:  true,
				DirtyWorkspace: true,
			},
			expected: Decision{
				State:           "failed",
				Reason:          "workspace contains dirty changes",
				FailureCategory: "dirty_workspace",
			},
		},
		{
			name: "conflict",
			input: DecisionInput{
				BridgeSuccess: true,
				Conflict:      true,
			},
			expected: Decision{
				State:           "failed",
				Reason:          "git merge conflict detected",
				FailureCategory: "conflict",
			},
		},
		{
			name: "develop match ready succeeds",
			input: DecisionInput{
				BridgeSuccess: true,
				DevelopMatch: roadmapsync.ProjectionCandidate{
					Ready:  true,
					Reason: "matched",
				},
			},
			expected: Decision{
				State:  "succeeded",
				Reason: "matched",
			},
		},
		{
			name: "develop match not ready is in_progress",
			input: DecisionInput{
				BridgeSuccess: true,
				DevelopMatch: roadmapsync.ProjectionCandidate{
					Ready:  false,
					Reason: "no revision yet",
				},
			},
			expected: Decision{
				State:  "in_progress",
				Reason: "no revision yet",
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := DecideAuthoringResult(tt.input)
			if got.State != tt.expected.State {
				t.Errorf("expected state %q, got %q", tt.expected.State, got.State)
			}
			if got.Reason != tt.expected.Reason {
				t.Errorf("expected reason %q, got %q", tt.expected.Reason, got.Reason)
			}
			if got.FailureCategory != tt.expected.FailureCategory {
				t.Errorf("expected failure category %q, got %q", tt.expected.FailureCategory, got.FailureCategory)
			}
		})
	}
}

func TestSlotStateForAuthoringOutcome(t *testing.T) {
	tests := []struct {
		name      string
		decision  Decision
		wantState projectsync.SlotState
		wantOK    bool
	}{
		{
			name:      "success releases slot",
			decision:  Decision{State: "succeeded"},
			wantState: projectsync.SlotStateAvailable,
			wantOK:    true,
		},
		{
			name:      "dirty workspace keeps slot dirty",
			decision:  Decision{State: "failed", FailureCategory: "dirty_workspace"},
			wantState: projectsync.SlotStateDirty,
			wantOK:    true,
		},
		{
			name:      "conflict keeps slot dirty",
			decision:  Decision{State: "failed", FailureCategory: "conflict"},
			wantState: projectsync.SlotStateDirty,
			wantOK:    true,
		},
		{
			name:      "push failure keeps slot dirty",
			decision:  Decision{State: "failed", FailureCategory: "push_failed"},
			wantState: projectsync.SlotStateDirty,
			wantOK:    true,
		},
		{
			name:      "bridge failure marks slot error",
			decision:  Decision{State: "failed", FailureCategory: "bridge_failed"},
			wantState: projectsync.SlotStateError,
			wantOK:    true,
		},
		{
			name:     "in progress is not terminal",
			decision: Decision{State: "in_progress"},
			wantOK:   false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			gotState, gotOK := SlotStateForAuthoringOutcome(tt.decision)
			if gotOK != tt.wantOK {
				t.Fatalf("expected ok=%v, got %v", tt.wantOK, gotOK)
			}
			if gotState != tt.wantState {
				t.Errorf("expected state %q, got %q", tt.wantState, gotState)
			}
		})
	}
}
