// Action-row lifetime across streaming, replay, and turn completion is not exercised by daemon E2E.
package tui

import (
	"strings"
	"testing"

	"albedo/cli/internal/daemon"
	"github.com/charmbracelet/x/ansi"
)

func TestGroupedActionRowHoldsUntilTheNextAction(t *testing.T) {
	m := newTestChatModel(t, &daemon.Session{ID: "s"})
	m.SetSize(100, 30)
	m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventUser, Text: "check it"})
	progress := func(kind, target string) {
		m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventToolProgress,
			Progress: &daemon.ToolProgress{Name: "python", Phase: "running",
				Intent: &daemon.ToolIntent{Kind: kind, Target: target}}})
	}
	finish := func(kind, target string) {
		m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventTool, ToolName: "python",
			ToolResult: `{"status":"ok"}`, ToolTrace: &daemon.ToolTrace{Activities: []daemon.ToolActivity{
				{Kind: kind, Target: target},
			}}})
	}
	visible := func() string {
		m.refreshViewportContent()
		return ansi.Strip(m.Viewport.View())
	}
	occupied := func() int {
		n := 0
		for row := range strings.SplitSeq(visible(), "\n") {
			if strings.TrimSpace(row) != "" {
				n++
			}
		}
		return n
	}

	progress("read", "first.go")
	finish("read", "first.go")
	if got := visible(); !strings.Contains(got, "read first.go") {
		t.Fatalf("completed read vanished: %q", got)
	}

	progress("run", "go test")
	before := occupied()
	m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventToolProgress})
	if got := visible(); !strings.Contains(got, "running go test") || occupied() != before {
		t.Fatalf("progress cleared before the result: %q", got)
	}
	finish("run", "go test")
	if got := visible(); !strings.Contains(got, "ran go test") || strings.Contains(got, "running go test") || occupied() != before {
		t.Fatalf("result removed the action row or changed its height: %q, before %d after %d", got, before, occupied())
	}

	progress("read", "next.go")
	if got := visible(); !strings.Contains(got, "reading next.go") || strings.Contains(got, "running go test") {
		t.Fatalf("the new action did not replace the last: %q", got)
	}
	finish("read", "next.go")
	m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventThinking, Text: "**Planning the next step**\nmore thought"})
	thinking := occupied()
	if got := visible(); !strings.Contains(got, "more thought…") || strings.Contains(got, "Planning the next step") || strings.Contains(got, "reading next.go") {
		t.Fatalf("thinking did not replace the tool action with its newest line: %q", got)
	}
	m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventUsage})
	if got := visible(); !strings.Contains(got, "more thought") || strings.Contains(got, "more thought…") || occupied() != thinking {
		t.Fatalf("finished thought removed its newest line: %q, before %d after %d", got, thinking, occupied())
	}
	m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventText, Text: "here's why"})
	if got := visible(); strings.Contains(got, "more thought") || !strings.Contains(got, "here's why") {
		t.Fatalf("prose did not replace the thought action: %q", got)
	}
}

func TestFinishedActionDoesNotLeakIntoVerboseOrReplayedHistory(t *testing.T) {
	m := newTestChatModel(t, &daemon.Session{ID: "s"})
	m.SetSize(100, 30)
	m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventTool, ToolName: "python", ToolResult: `{"status":"ok"}`})
	if m.ToolProgressText == "" {
		t.Fatal("no completed tool preview")
	}
	m.Flags.Tools = true
	m.refreshViewportContent()
	if strings.Contains(ansi.Strip(m.Viewport.View()), "used python") {
		t.Fatal("the completed preview duplicated the verbose tool row")
	}
	m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventReset})
	m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventToolProgress, Replayed: true,
		Progress: &daemon.ToolProgress{Name: "python", Phase: "running"}})
	m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventTool, ToolName: "python", Replayed: true})
	if m.ToolProgressText != "" || m.ThoughtProgressText != "" {
		t.Fatal("replaying old history produced a live action row")
	}
}

func TestTurnSignoffReplacesTheLastActionRow(t *testing.T) {
	m := newTestChatModel(t, &daemon.Session{ID: "s"})
	m.SetSize(100, 30)
	m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventUser, Text: "do it"})
	m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventToolProgress,
		Progress: &daemon.ToolProgress{Name: "python", Phase: "running"}})
	m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventTool, ToolName: "python",
		ToolArgs: map[string]any{"code": "print(42)"}, ToolResult: `{"status":"ok"}`})
	m.refreshViewportContent()
	view := ansi.Strip(m.Viewport.View())
	if strings.Count(view, "python · print(42)") != 1 || !strings.Contains(view, "python print(42)") {
		t.Fatalf("group summary and completed action are not both visible: %q", view)
	}
	status := daemon.AgentStatus{Idle: true}
	m, _ = m.Update(ChatStatusMsg{SessionID: m.SessionID, Generation: m.Generation,
		Revision: m.statusRevision, Status: &status})
	if m.ToolProgressText != "" || strings.Contains(ansi.Strip(m.Viewport.View()), "python · print(42)") ||
		!strings.Contains(ansi.Strip(m.Viewport.View()), "python print(42)") {
		t.Fatalf("turn signoff left an action row behind: %q", m.Viewport.View())
	}
}
