package app

import (
	"strings"
	"testing"

	"charm.land/lipgloss/v2"
)

// inSessionModel builds an in-session model with deliberately long fields (model name,
// session name, workspace) that would overflow a slim status bar if not truncated.
func inSessionModel(w, h int) Model {
	m := NewModel(nil)
	m.width, m.height = w, h
	m.connected = true
	m.currentModel = "llama-cpp:a-very-long-local-model-identifier-here"
	m.sessions = []Session{{
		ID: "abcdef123456", Status: "FAILED", WorkflowID: "healthcheck",
		Name: "a-rather-long-session-name", CurrentStage: "write_script",
		WorkspaceRoot: "/home/kami/Programs/correx/some/deep/path",
		LastEventAt:   nowMillis(), Active: true,
	}}
	m.selectedID = "abcdef123456"
	m.sessionEntered = true
	m.routerMessages["abcdef123456"] = []RouterEntry{{Role: "router", Content: strings.Repeat("word ", 60)}}
	return m
}

func assertNoOverflow(t *testing.T, out string, w int) {
	t.Helper()
	for i, ln := range strings.Split(out, "\n") {
		if vw := lipgloss.Width(ln); vw > w {
			t.Errorf("line %d visible width %d > terminal width %d: %q", i, vw, w, ln)
		}
	}
}

// The whole frame must fit the terminal at every width — no status/footer/panel line
// may overflow (the bug: justify never truncated, so slim terminals smeared).
func TestViewNeverOverflowsWidth(t *testing.T) {
	for _, w := range []int{40, 50, 60, 80, 95, 96, 110, 160} {
		m := inSessionModel(w, 30)
		assertNoOverflow(t, m.render(), w)
	}
}

// The stats overlay must also stay within the terminal at narrow widths.
func TestStatsOverlayNeverOverflowsWidth(t *testing.T) {
	for _, w := range []int{50, 64, 80, 120} {
		m := inSessionModel(w, 40)
		m.overlay = OverlayStats
		m.statsFor = m.selectedID
		m.stats = sampleStats()
		assertNoOverflow(t, m.render(), w)
	}
}

// Below the threshold the main area collapses to a single column (vertically stacked
// in-session); above it the two-column split returns.
func TestNarrowCollapsesMainColumns(t *testing.T) {
	narrow := inSessionModel(70, 30)
	if !narrow.narrow() {
		t.Fatalf("width 70 should be narrow")
	}
	wide := inSessionModel(120, 30)
	if wide.narrow() {
		t.Fatalf("width 120 should not be narrow")
	}
	// In-session narrow main stacks output over events: both titles present, one per row.
	out := narrow.renderMainNarrow(20)
	if !strings.Contains(out, "OUTPUT") || !strings.Contains(out, "EVENTS") {
		t.Errorf("narrow in-session main should stack OUTPUT and EVENTS, got:\n%s", out)
	}
}
