package tui

import (
	"strings"
	"testing"

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

// newTestStatusBar builds a status bar with a known cwd (already ~-abbreviated
// by the caller's intent) so tests do not depend on the real $HOME.
func newTestStatusBar() statusBar {
	opts := Options{Model: "claude-opus", ThinkingLevel: agentcore.ThinkingHigh}
	s := newStatusBar(DefaultTheme(), opts, "/tmp/project")
	s.cwd = "~/project"
	return s
}

func TestStatusBarRendersAllFields(t *testing.T) {
	s := newTestStatusBar()
	s.SetGit(gitInfoMsg{branch: "master", dirty: 3, ahead: 4, ok: true})
	s.SetTelemetry(telemetryEventView{util: 0.42, window: 200000})
	s.SetTask("running: Read")

	const width = 200
	out := s.Render(width)

	for _, want := range []string{
		"pigo",          // app badge
		"claude-opus",   // model
		"high",          // thinking level
		"~/project",     // cwd
		"master",        // git branch
		glyphDirty + "3", // dirty marker
		glyphAhead + "4", // ahead marker
		"42%",           // context usage
		"running: Read", // task
	} {
		if !strings.Contains(out, want) {
			t.Errorf("render missing %q; got %q", want, out)
		}
	}

	if w := ui.Width(out); w > width {
		t.Errorf("render width %d exceeds terminal width %d", w, width)
	}
}

func TestStatusBarHidesGitWhenNotRepo(t *testing.T) {
	s := newTestStatusBar()
	s.SetGit(gitInfoMsg{ok: false})

	out := s.Render(120)
	if strings.Contains(out, "master") || strings.Contains(out, "*") || strings.Contains(out, "+") {
		t.Errorf("git segment should be hidden when ok=false; got %q", out)
	}
}

func TestStatusBarHidesContextWhenUnknown(t *testing.T) {
	s := newTestStatusBar()
	// No telemetry set (window 0) → context segment hidden.
	s.SetTelemetry(telemetryEventView{util: 0.5, window: 0})

	out := s.Render(120)
	if strings.Contains(out, glyphCtx) {
		t.Errorf("context segment should be hidden when window unknown; got %q", out)
	}
}

func TestStatusBarTruncationKeepsPriorityFields(t *testing.T) {
	s := newTestStatusBar()
	s.SetGit(gitInfoMsg{branch: "master", dirty: 3, ahead: 4, ok: true})
	s.SetTelemetry(telemetryEventView{util: 0.42, window: 200000})
	s.SetTask("TASK")

	// Narrow width: only the highest-priority fields (task > model > token)
	// should survive; cwd and git should drop first.
	const width = 24
	out := s.Render(width)

	if w := ui.Width(out); w > width {
		t.Fatalf("truncated render width %d exceeds %d: %q", w, width, out)
	}
	if !strings.Contains(out, "TASK") {
		t.Errorf("highest-priority task field dropped under truncation: %q", out)
	}
	// cwd (lowest priority) must be gone before task.
	if strings.Contains(out, "~/project") {
		t.Errorf("lowest-priority cwd should drop first under truncation: %q", out)
	}
}

func TestStatusBarVeryNarrowNeverOverflows(t *testing.T) {
	s := newTestStatusBar()
	s.SetTask("a-fairly-long-task-description-that-cannot-fit")

	for _, width := range []int{1, 2, 3, 5, 8} {
		out := s.Render(width)
		if w := ui.Width(out); w > width {
			t.Errorf("width %d: render width %d overflows: %q", width, w, out)
		}
	}
}

func TestStatusBarZeroWidthEmpty(t *testing.T) {
	s := newTestStatusBar()
	if out := s.Render(0); out != "" {
		t.Errorf("zero width should render empty, got %q", out)
	}
}

// TestStatusBarContextTokenCount checks the context segment shows a
// comma-grouped token count with the percentage once telemetry reports tokens.
func TestStatusBarContextTokenCount(t *testing.T) {
	s := newTestStatusBar()
	s.SetTelemetry(telemetryEventView{util: 0.46, window: 200000, tokens: 90866})

	out := s.Render(200)
	for _, want := range []string{glyphCtx, "90,866", "46%"} {
		if !strings.Contains(out, want) {
			t.Errorf("render missing %q; got %q", want, out)
		}
	}
}

func TestHumanizeInt(t *testing.T) {
	cases := map[int]string{0: "0", 90866: "90,866", 1000: "1,000", 999: "999", 1234567: "1,234,567"}
	for in, want := range cases {
		if got := humanizeInt(in); got != want {
			t.Errorf("humanizeInt(%d) = %q, want %q", in, got, want)
		}
	}
}

func TestAbbreviateHome(t *testing.T) {
	home := homeDir()
	if home == "" {
		t.Skip("no home dir available")
	}
	if got := abbreviateHome(home); got != "~" {
		t.Errorf("abbreviateHome(home) = %q, want ~", got)
	}
	if got := abbreviateHome(home + "/foo/bar"); got != "~/foo/bar" {
		t.Errorf("abbreviateHome(home/foo/bar) = %q, want ~/foo/bar", got)
	}
	if got := abbreviateHome("/etc/passwd"); got != "/etc/passwd" {
		t.Errorf("abbreviateHome(/etc/passwd) = %q, want unchanged", got)
	}
}

// TestStatusBarGitTextFormatting checks the "*N +N" markers appear only when
// non-zero.
func TestStatusBarGitTextFormatting(t *testing.T) {
	s := newTestStatusBar()
	s.SetGit(gitInfoMsg{branch: "main", ok: true})
	out := s.Render(120)
	if strings.Contains(out, "*") || strings.Contains(out, "+") {
		t.Errorf("clean tree should show no *N/+N markers: %q", out)
	}
	if !strings.Contains(out, "main") {
		t.Errorf("branch name missing: %q", out)
	}
}
