package app

import (
	"encoding/json"
	"strings"
	"testing"

	"github.com/correx/tui-go/internal/protocol"
	"github.com/correx/tui-go/internal/ws"
)

func ideaModel() (Model, *ws.Client) {
	client := ws.New("", 0) // unconnected; Send buffers, Drain reads it back
	m := NewModel(client)
	m.width, m.height = 120, 40
	m.theme = NewTheme(SoftBlue)
	m.openIdeas() // sets OverlayIdeas + sends a ListIdeas frame
	m.applyServer(protocol.ServerMessage{
		Type: protocol.TypeIdeaList,
		Ideas: []protocol.IdeaDto{
			{IdeaID: "i1", Text: "cache the repo map", CapturedAtMs: 1000},
			{IdeaID: "i2", Text: "add --dry-run", CapturedAtMs: 2000},
		},
	})
	return m, client
}

func TestIdeaBoardOpensAndRenders(t *testing.T) {
	m, _ := ideaModel()
	if m.overlay != OverlayIdeas {
		t.Fatalf("want OverlayIdeas, got %v", m.overlay)
	}
	out := m.ideasModal()
	for _, want := range []string{"ideas", "cache the repo map", "add --dry-run"} {
		if !strings.Contains(out, want) {
			t.Fatalf("board missing %q:\n%s", want, out)
		}
	}
}

func TestIdeaRemoveSendsDiscardAndDropsRow(t *testing.T) {
	m, client := ideaModel()
	_ = client.Drain() // drop the ListIdeas frame from openIdeas

	updated, _ := m.handleOverlayKey(keyMsg{Type: keyRunes, Runes: []rune("x")})
	m = updated.(Model)

	if len(m.ideas) != 1 || m.ideas[0].IdeaID != "i2" {
		t.Fatalf("expected i1 removed, got %+v", m.ideas)
	}
	frames := client.Drain()
	if len(frames) != 1 {
		t.Fatalf("expected one DiscardIdea frame, got %d", len(frames))
	}
	var raw map[string]any
	if err := json.Unmarshal(frames[0], &raw); err != nil {
		t.Fatalf("unmarshal: %v", err)
	}
	if raw["type"] != "com.correx.apps.server.protocol.ClientMessage.DiscardIdea" || raw["ideaId"] != "i1" {
		t.Fatalf("expected DiscardIdea i1, got %+v", raw)
	}
}

func TestIdeaBoardEmptyState(t *testing.T) {
	m, _ := ideaModel()
	m.applyServer(protocol.ServerMessage{Type: protocol.TypeIdeaList, Ideas: nil})
	if !strings.Contains(m.ideasModal(), "no ideas yet") {
		t.Fatalf("expected empty state, got:\n%s", m.ideasModal())
	}
}
