package orchestrator

import (
	"testing"

	"github.com/google/uuid"

	"github.com/yan1h/agent-coding-workflow/internal/project"
)

func TestNextPhase_AdvancesLinearly(t *testing.T) {
	pass := GateResult{Pass: true}
	cases := []struct {
		from     project.Phase
		wantNext project.Phase
		wantTerm bool
	}{
		{project.PhasePlanning, project.PhasePrototyping, false},
		{project.PhasePrototyping, project.PhaseAuditing, false},
		{project.PhaseAuditing, project.PhaseImplementing, false},
		{project.PhaseImplementing, project.PhaseReviewing, false},
		{project.PhaseReviewing, project.PhaseDone, false},
		{project.PhaseDone, project.PhaseDone, true},
	}
	for _, c := range cases {
		next, term := NextPhase(c.from, pass)
		if next != c.wantNext || term != c.wantTerm {
			t.Errorf("NextPhase(%s,pass) = (%s,%v); want (%s,%v)",
				c.from, next, term, c.wantNext, c.wantTerm)
		}
	}
}

func TestNextPhase_GateFailLoopsBack(t *testing.T) {
	fail := GateResult{Pass: false, Retry: true}
	for _, ph := range project.AllPhases {
		next, term := NextPhase(ph, fail)
		if next != ph || term {
			t.Errorf("NextPhase(%s, fail) = (%s,%v); want (%s,false)", ph, next, term, ph)
		}
	}
}

func TestNextPhase_UnknownPhaseTerminates(t *testing.T) {
	next, term := NextPhase(project.Phase("bogus"), GateResult{Pass: true})
	if !term {
		t.Errorf("unknown phase should terminate; got next=%s term=%v", next, term)
	}
}

func TestPhaseAgentKind_OverridePreferredThenDefault(t *testing.T) {
	override := uuid.New()
	def := uuid.New()
	cfg := RunConfig{PhaseAgentKinds: map[project.Phase]uuid.UUID{project.PhasePlanning: override}}
	defaults := map[project.Phase]uuid.UUID{project.PhasePlanning: def, project.PhaseAuditing: def}

	got, err := PhaseAgentKind(cfg, project.PhasePlanning, defaults)
	if err != nil || got != override {
		t.Fatalf("override path: got=%s err=%v; want %s", got, err, override)
	}

	got, err = PhaseAgentKind(cfg, project.PhaseAuditing, defaults)
	if err != nil || got != def {
		t.Fatalf("default fallback: got=%s err=%v; want %s", got, err, def)
	}
}

func TestPhaseAgentKind_MissingErrors(t *testing.T) {
	_, err := PhaseAgentKind(RunConfig{}, project.PhasePlanning, nil)
	if err == nil {
		t.Fatal("expected error when no agent kind configured")
	}
}

func TestBuildPrompt_IncludesReqAndArtifacts(t *testing.T) {
	req := &project.Requirement{Number: 7, Title: "Login flow", Description: "Add OAuth login"}
	arts := []*project.Artifact{
		{Phase: project.PhasePlanning, Version: 2, Content: "Plan: use OAuth2 PKCE\nmore detail"},
	}
	out := BuildPrompt(project.PhaseAuditing, req, arts, "")
	for _, want := range []string{"#7", "Login flow", "Add OAuth login", "Plan: use OAuth2 PKCE", "auditing"} {
		if !contains(out, want) {
			t.Errorf("prompt missing %q\n%s", want, out)
		}
	}
}

func TestBuildPrompt_OverrideUsed(t *testing.T) {
	req := &project.Requirement{Number: 1, Title: "T"}
	out := BuildPrompt(project.PhasePlanning, req, nil, "DO THE SPECIAL THING")
	if !contains(out, "DO THE SPECIAL THING") {
		t.Errorf("override not used:\n%s", out)
	}
	if contains(out, "Produce a clear plan") {
		t.Errorf("default instruction should be suppressed when override present:\n%s", out)
	}
}

func contains(s, sub string) bool {
	return len(s) >= len(sub) && (indexOf(s, sub) >= 0)
}

func indexOf(s, sub string) int {
	for i := 0; i+len(sub) <= len(s); i++ {
		if s[i:i+len(sub)] == sub {
			return i
		}
	}
	return -1
}
