package tui

import (
	"strings"
	"testing"
)

func TestVTRender(t *testing.T) {
	t.Run("layout absoluto basico A y B separados por movimiento de cursor", func(t *testing.T) {
		// ESC[1;5H mueve el cursor a fila 1 columna 5 (1-indexed).
		// Resultado esperado: 'A' en col 1, espacios, 'B' en col 5.
		out := VTRender("A\x1b[1;5HB", 2, 10)
		lines := strings.Split(out, "\n")
		if len(lines) == 0 {
			t.Fatalf("resultado vacio")
		}
		first := lines[0]
		if len(first) < 5 {
			t.Fatalf("linea demasiado corta: %q", first)
		}
		if first[0] != 'A' {
			t.Errorf("esperaba 'A' en columna 0, got %q en linea %q", string(first[0]), first)
		}
		if first[4] != 'B' {
			t.Errorf("esperaba 'B' en columna 4 (0-indexed), got %q en linea %q", string(first[4]), first)
		}
		// Verificar que hay espacios entre A y B (no están pegadas).
		if strings.Contains(first, "AB") {
			t.Errorf("A y B estan pegadas en %q, deberían estar separadas", first)
		}
	})

	t.Run("dos palabras separadas por movimiento de columna no aparecen pegadas", func(t *testing.T) {
		// ESC[10G mueve el cursor a la columna 10 (1-indexed) de la línea actual.
		out := VTRender("foo\x1b[10Gbar", 2, 20)
		lines := strings.Split(out, "\n")
		if len(lines) == 0 {
			t.Fatalf("resultado vacio")
		}
		first := lines[0]
		if strings.Contains(first, "foobar") {
			t.Errorf("foo y bar estan pegadas: %q — esperaba espacios entre ellas", first)
		}
		if !strings.Contains(first, "foo") {
			t.Errorf("no encontre 'foo' en %q", first)
		}
		if !strings.Contains(first, "bar") {
			t.Errorf("no encontre 'bar' en %q", first)
		}
		// foo en col 0-2, bar en col 9-11 (columna 10 es 0-indexed 9).
		if len(first) < 12 {
			t.Fatalf("linea demasiado corta para verificar: %q", first)
		}
		// Debe haber al menos un espacio entre foo y bar.
		fooEnd := strings.Index(first, "foo") + 3
		barStart := strings.Index(first, "bar")
		if barStart <= fooEnd {
			t.Errorf("bar empieza en %d pero foo termina en %d — sin separacion en %q", barStart, fooEnd, first)
		}
	})

	t.Run("texto multilinea simple con CRLF", func(t *testing.T) {
		out := VTRender("linea1\r\nlinea2", 5, 40)
		if !strings.Contains(out, "linea1") {
			t.Errorf("no encontre 'linea1' en %q", out)
		}
		if !strings.Contains(out, "linea2") {
			t.Errorf("no encontre 'linea2' en %q", out)
		}
		lines := strings.Split(out, "\n")
		// linea1 y linea2 deben estar en líneas distintas.
		found1, found2 := -1, -1
		for i, l := range lines {
			if strings.Contains(l, "linea1") {
				found1 = i
			}
			if strings.Contains(l, "linea2") {
				found2 = i
			}
		}
		if found1 == found2 {
			t.Errorf("linea1 y linea2 estan en la misma linea (%d) de la salida: %q", found1, out)
		}
	})

	t.Run("trim de filas vacias al final de grid grande", func(t *testing.T) {
		// Input corto en un grid de 40 filas — no debe producir 40 lineas.
		out := VTRender("hola", 40, 120)
		count := strings.Count(out, "\n")
		if count >= 3 {
			t.Errorf("demasiadas lineas (%d) para 'hola' en grid de 40 filas: %q", count, out)
		}
		if !strings.Contains(out, "hola") {
			t.Errorf("no encontre 'hola' en %q", out)
		}
	})

	t.Run("determinismo misma entrada misma salida", func(t *testing.T) {
		input := "foo\x1b[10Gbar\r\n\x1b[2;1Hbaz"
		out1 := VTRender(input, 10, 40)
		out2 := VTRender(input, 10, 40)
		if out1 != out2 {
			t.Errorf("resultados distintos:\nout1=%q\nout2=%q", out1, out2)
		}
	})

	t.Run("defaults rows y cols al pasar cero", func(t *testing.T) {
		// Verificar que no entra en pánico con valores <= 0.
		out := VTRender("test", 0, 0)
		if !strings.Contains(out, "test") {
			t.Errorf("no encontre 'test' con defaults (rows=0,cols=0): %q", out)
		}
	})
}
