package ai

import (
	"fmt"
	"sync"
	"testing"
)

func TestWriteAndRead(t *testing.T) {
	buf := NewTerminalBuffer(100)

	buf.Write([]byte("line1\nline2\nline3\n"))

	all := buf.ReadAll()
	if len(all) != 3 {
		t.Fatalf("expected 3 lines, got %d", len(all))
	}
	if all[0] != "line1" || all[1] != "line2" || all[2] != "line3" {
		t.Errorf("unexpected lines: %v", all)
	}
}

func TestRingBufferOverflow(t *testing.T) {
	buf := NewTerminalBuffer(200)

	// Write 300 lines
	for i := 0; i < 300; i++ {
		buf.Write([]byte(fmt.Sprintf("line %d\n", i)))
	}

	all := buf.ReadAll()
	if len(all) != 200 {
		t.Fatalf("expected 200 lines (ring buffer), got %d", len(all))
	}

	// First line should be "line 100" (oldest retained)
	if all[0] != "line 100" {
		t.Errorf("expected first line 'line 100', got %q", all[0])
	}

	// Last line should be "line 299"
	if all[199] != "line 299" {
		t.Errorf("expected last line 'line 299', got %q", all[199])
	}
}

func TestReadLastSubset(t *testing.T) {
	buf := NewTerminalBuffer(100)

	buf.Write([]byte("a\nb\nc\nd\ne\n"))

	last3 := buf.ReadLast(3)
	if len(last3) != 3 {
		t.Fatalf("expected 3 lines, got %d", len(last3))
	}
	if last3[0] != "c" || last3[1] != "d" || last3[2] != "e" {
		t.Errorf("unexpected lines: %v", last3)
	}

	// Request more than available
	last10 := buf.ReadLast(10)
	if len(last10) != 5 {
		t.Fatalf("expected 5 lines (all available), got %d", len(last10))
	}
}

func TestConcurrentAccess(t *testing.T) {
	buf := NewTerminalBuffer(1000)

	var wg sync.WaitGroup

	// Spawn 10 writers
	for w := 0; w < 10; w++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			for i := 0; i < 100; i++ {
				buf.Write([]byte(fmt.Sprintf("writer %d line %d\n", id, i)))
			}
		}(w)
	}

	// Spawn 5 readers
	for r := 0; r < 5; r++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for i := 0; i < 100; i++ {
				_ = buf.ReadLast(10)
				_ = buf.Len()
			}
		}()
	}

	wg.Wait()

	total := buf.Len()
	if total != 1000 {
		t.Errorf("expected 1000 lines (10 writers * 100), got %d", total)
	}
}

func TestWritePartialLines(t *testing.T) {
	buf := NewTerminalBuffer(100)

	// Write data without trailing newline
	buf.Write([]byte("partial"))

	// Should have no complete lines yet
	if buf.Len() != 0 {
		t.Errorf("expected 0 lines for partial write, got %d", buf.Len())
	}

	// Complete the line
	buf.Write([]byte(" line\n"))

	if buf.Len() != 1 {
		t.Fatalf("expected 1 line after completing partial, got %d", buf.Len())
	}

	all := buf.ReadAll()
	if all[0] != "partial line" {
		t.Errorf("expected 'partial line', got %q", all[0])
	}
}

func TestWriteMultiplePartials(t *testing.T) {
	buf := NewTerminalBuffer(100)

	buf.Write([]byte("hello "))
	buf.Write([]byte("world"))
	buf.Write([]byte("!\nfoo\n"))

	all := buf.ReadAll()
	if len(all) != 2 {
		t.Fatalf("expected 2 lines, got %d: %v", len(all), all)
	}
	if all[0] != "hello world!" {
		t.Errorf("expected 'hello world!', got %q", all[0])
	}
	if all[1] != "foo" {
		t.Errorf("expected 'foo', got %q", all[1])
	}
}

func TestClear(t *testing.T) {
	buf := NewTerminalBuffer(100)

	buf.Write([]byte("line1\nline2\n"))
	buf.Clear()

	if buf.Len() != 0 {
		t.Errorf("expected 0 lines after clear, got %d", buf.Len())
	}
}

func TestReadLastZero(t *testing.T) {
	buf := NewTerminalBuffer(100)
	buf.Write([]byte("line\n"))

	result := buf.ReadLast(0)
	if len(result) != 0 {
		t.Errorf("expected empty result for ReadLast(0), got %d lines", len(result))
	}
}

func TestReadLastNegative(t *testing.T) {
	buf := NewTerminalBuffer(100)
	buf.Write([]byte("line\n"))

	result := buf.ReadLast(-1)
	if len(result) != 0 {
		t.Errorf("expected empty result for ReadLast(-1), got %d lines", len(result))
	}
}
