package screens

import (
	"testing"

	tea "charm.land/bubbletea/v2"

	"git.secluded.site/keld/internal/ui"
)

func TestTargetTitle(t *testing.T) {
	t.Parallel()

	tgt := NewTarget(testStyles())
	if got := tgt.Title(); got != "Target directory" {
		t.Errorf("Title() = %q, want %q", got, "Target directory")
	}
}

func TestTargetSelectionEmpty(t *testing.T) {
	t.Parallel()

	tgt := NewTarget(testStyles())
	if got := tgt.Selection(); got != "" {
		t.Errorf("Selection() before interaction = %q, want empty", got)
	}
}

func TestTargetKeyBindings(t *testing.T) {
	t.Parallel()

	tgt := NewTarget(testStyles())
	bindings := tgt.KeyBindings()

	if len(bindings) == 0 {
		t.Fatal("KeyBindings() returned no bindings")
	}
}

func TestTargetEscReturnsBack(t *testing.T) {
	t.Parallel()

	tgt := NewTarget(testStyles())
	tgt.Init()
	tgt.Update(tea.WindowSizeMsg{Width: 80, Height: 20})

	_, cmd := tgt.Update(tea.KeyPressMsg{Code: tea.KeyEscape})

	if cmd == nil {
		t.Fatal("expected BackCmd on Esc")
	}
	msg := cmd()
	if _, ok := msg.(ui.BackMsg); !ok {
		t.Errorf("cmd produced %T, want ui.BackMsg", msg)
	}
}

func TestTargetCompleteReturnsDone(t *testing.T) {
	t.Parallel()

	tgt := NewTarget(testStyles())
	tgt.Init()
	tgt.Update(tea.WindowSizeMsg{Width: 80, Height: 20})

	// Type a path, then press enter.
	for _, ch := range "/tmp/restore" {
		tgt.Update(tea.KeyPressMsg{Code: ch, Text: string(ch)})
	}

	var screen ui.Screen
	var cmd tea.Cmd
	screen, cmd = tgt.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
	_, cmd = drain(screen.(*Target), cmd)

	if cmd == nil {
		t.Fatal("expected DoneCmd after form completion")
	}
	msg := cmd()
	if _, ok := msg.(ui.DoneMsg); !ok {
		t.Errorf("cmd produced %T, want ui.DoneMsg", msg)
	}
}

func TestTargetSelectionShowsPath(t *testing.T) {
	t.Parallel()

	tgt := NewTarget(testStyles())
	tgt.Init()
	tgt.Update(tea.WindowSizeMsg{Width: 80, Height: 20})

	for _, ch := range "/tmp/restore" {
		tgt.Update(tea.KeyPressMsg{Code: ch, Text: string(ch)})
	}

	var screen ui.Screen
	var cmd tea.Cmd
	screen, cmd = tgt.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
	tgt, _ = drain(screen.(*Target), cmd)

	if got := tgt.Selection(); got != "/tmp/restore" {
		t.Errorf("Selection() = %q, want %q", got, "/tmp/restore")
	}
}

func TestTargetValueReturnsPath(t *testing.T) {
	t.Parallel()

	tgt := NewTarget(testStyles())
	tgt.Init()
	tgt.Update(tea.WindowSizeMsg{Width: 80, Height: 20})

	for _, ch := range "/tmp/restore" {
		tgt.Update(tea.KeyPressMsg{Code: ch, Text: string(ch)})
	}

	var screen ui.Screen
	var cmd tea.Cmd
	screen, cmd = tgt.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
	tgt, _ = drain(screen.(*Target), cmd)

	if got := tgt.Value(); got != "/tmp/restore" {
		t.Errorf("Value() = %q, want %q", got, "/tmp/restore")
	}
}

func TestTargetReinitAfterBack(t *testing.T) {
	t.Parallel()

	tgt := NewTarget(testStyles())
	tgt.Init()
	tgt.Update(tea.WindowSizeMsg{Width: 80, Height: 20})

	// Complete the form.
	for _, ch := range "/tmp/restore" {
		tgt.Update(tea.KeyPressMsg{Code: ch, Text: string(ch)})
	}
	var screen ui.Screen
	var cmd tea.Cmd
	screen, cmd = tgt.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
	tgt, _ = drain(screen.(*Target), cmd)

	// Re-init (simulates back navigation).
	tgt.Init()
	tgt.Update(tea.WindowSizeMsg{Width: 80, Height: 20})

	// Should be functional again.
	for _, ch := range "/var/data" {
		tgt.Update(tea.KeyPressMsg{Code: ch, Text: string(ch)})
	}
	screen, cmd = tgt.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
	_, cmd = drain(screen.(*Target), cmd)

	if cmd == nil {
		t.Fatal("expected DoneCmd after re-init")
	}
	msg := cmd()
	if _, ok := msg.(ui.DoneMsg); !ok {
		t.Errorf("after re-init, cmd produced %T, want ui.DoneMsg", msg)
	}
}

func TestTargetPreservesValueOnReinit(t *testing.T) {
	t.Parallel()

	tgt := NewTarget(testStyles())
	tgt.Init()
	tgt.Update(tea.WindowSizeMsg{Width: 80, Height: 20})

	for _, ch := range "/tmp/restore" {
		tgt.Update(tea.KeyPressMsg{Code: ch, Text: string(ch)})
	}
	var screen ui.Screen
	var cmd tea.Cmd
	screen, cmd = tgt.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
	tgt, _ = drain(screen.(*Target), cmd)

	// Re-init should preserve the entered value.
	tgt.Init()

	if tgt.entered != "/tmp/restore" {
		t.Errorf("after re-init, entered = %q, want %q", tgt.entered, "/tmp/restore")
	}
}
