package run

// Tests for resolveThinkingLevel: the CLI end of the layered config chain
// (US-023). It resolves the effective reasoning-effort level through
// default < global ($PIGO_HOME/config.json) < project (./.pigo/config.json)
// < env (PIGO_THINKING_LEVEL) < --thinking-level flag, and rejects an invalid
// value. Each test isolates PIGO_HOME and the working directory so it never
// reads the developer's real config.

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/smallnest/pigo/internal/agentcore"
)

// isolateConfig points PIGO_HOME at a temp dir and chdir's into a temp working
// directory (restored on cleanup), so no real global/project config leaks in.
func isolateConfig(t *testing.T) string {
	t.Helper()
	home := t.TempDir()
	t.Setenv("PIGO_HOME", home)
	t.Setenv("PIGO_THINKING_LEVEL", "")

	wd := t.TempDir()
	prev, err := os.Getwd()
	if err != nil {
		t.Fatalf("getwd: %v", err)
	}
	if err := os.Chdir(wd); err != nil {
		t.Fatalf("chdir: %v", err)
	}
	t.Cleanup(func() { _ = os.Chdir(prev) })
	return home
}

// writeConfig writes a config.json layer with the given thinkingLevel at path.
func writeConfig(t *testing.T, path, level string) {
	t.Helper()
	if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
		t.Fatalf("mkdir: %v", err)
	}
	body := `{"thinkingLevel":"` + level + `"}`
	if err := os.WriteFile(path, []byte(body), 0o644); err != nil {
		t.Fatalf("write config: %v", err)
	}
}

// TestResolveThinkingLevelDefault verifies the built-in default (medium) applies
// when no layer sets a level.
func TestResolveThinkingLevelDefault(t *testing.T) {
	isolateConfig(t)
	got, err := ResolveThinkingLevel("")
	if err != nil {
		t.Fatalf("resolve: %v", err)
	}
	if got != agentcore.ThinkingMedium {
		t.Errorf("level = %q, want medium", got)
	}
}

// TestResolveThinkingLevelFlagWins verifies the --thinking-level flag overrides
// every lower layer (global, project, and env).
func TestResolveThinkingLevelFlagWins(t *testing.T) {
	home := isolateConfig(t)
	writeConfig(t, filepath.Join(home, "config.json"), "low")
	writeConfig(t, filepath.Join(".pigo", "config.json"), "high")
	t.Setenv("PIGO_THINKING_LEVEL", "minimal")

	got, err := ResolveThinkingLevel("xhigh")
	if err != nil {
		t.Fatalf("resolve: %v", err)
	}
	if got != agentcore.ThinkingXHigh {
		t.Errorf("level = %q, want xhigh (flag wins)", got)
	}
}

// TestResolveThinkingLevelEnvOverProject verifies env beats project, and project
// beats global (precedence: global < project < env).
func TestResolveThinkingLevelEnvOverProject(t *testing.T) {
	home := isolateConfig(t)
	writeConfig(t, filepath.Join(home, "config.json"), "low")
	writeConfig(t, filepath.Join(".pigo", "config.json"), "high")
	t.Setenv("PIGO_THINKING_LEVEL", "off")

	got, err := ResolveThinkingLevel("")
	if err != nil {
		t.Fatalf("resolve: %v", err)
	}
	if got != agentcore.ThinkingOff {
		t.Errorf("level = %q, want off (env over project/global)", got)
	}
}

// TestResolveThinkingLevelProjectOverGlobal verifies the project layer overrides
// the global layer when env and flag are unset.
func TestResolveThinkingLevelProjectOverGlobal(t *testing.T) {
	home := isolateConfig(t)
	writeConfig(t, filepath.Join(home, "config.json"), "low")
	writeConfig(t, filepath.Join(".pigo", "config.json"), "high")

	got, err := ResolveThinkingLevel("")
	if err != nil {
		t.Fatalf("resolve: %v", err)
	}
	if got != agentcore.ThinkingHigh {
		t.Errorf("level = %q, want high (project over global)", got)
	}
}

// TestResolveThinkingLevelInvalid verifies an unknown value is a hard error
// (surfaced for exit-code mapping), not silently coerced.
func TestResolveThinkingLevelInvalid(t *testing.T) {
	isolateConfig(t)
	if _, err := ResolveThinkingLevel("turbo"); err == nil {
		t.Error("expected error for invalid thinking level, got nil")
	}
}
