package ai

import (
	"strings"
	"sync"
)

// TerminalBuffer is a thread-safe ring buffer that captures terminal output lines.
// It is written to by SSH read loops and read by the AI tool dispatch for terminal_read.
type TerminalBuffer struct {
	lines   []string
	mu      sync.RWMutex
	max     int
	partial string // accumulates data that doesn't end with \n
}

// NewTerminalBuffer creates a buffer that retains at most maxLines lines.
func NewTerminalBuffer(maxLines int) *TerminalBuffer {
	if maxLines <= 0 {
		maxLines = 200
	}
	return &TerminalBuffer{
		lines: make([]string, 0, maxLines),
		max:   maxLines,
	}
}

// Write ingests raw terminal output, splitting on newlines and appending complete lines.
// Partial lines (data without a trailing newline) are accumulated until the next Write.
func (b *TerminalBuffer) Write(data []byte) {
	b.mu.Lock()
	defer b.mu.Unlock()

	text := b.partial + string(data)
	b.partial = ""

	parts := strings.Split(text, "\n")

	// The last element of Split is always either:
	// - empty string if text ends with \n (discard it)
	// - a partial line if text doesn't end with \n (save as partial)
	last := parts[len(parts)-1]
	parts = parts[:len(parts)-1]
	if last != "" {
		b.partial = last
	}

	for _, line := range parts {
		b.lines = append(b.lines, line)
	}

	// Trim to max
	if len(b.lines) > b.max {
		excess := len(b.lines) - b.max
		b.lines = b.lines[excess:]
	}
}

// ReadLast returns the last n lines from the buffer.
// If fewer than n lines are available, all lines are returned.
func (b *TerminalBuffer) ReadLast(n int) []string {
	b.mu.RLock()
	defer b.mu.RUnlock()

	total := len(b.lines)
	if n > total {
		n = total
	}
	if n <= 0 {
		return []string{}
	}

	result := make([]string, n)
	copy(result, b.lines[total-n:])
	return result
}

// ReadAll returns all lines currently in the buffer.
func (b *TerminalBuffer) ReadAll() []string {
	b.mu.RLock()
	defer b.mu.RUnlock()

	result := make([]string, len(b.lines))
	copy(result, b.lines)
	return result
}

// Clear removes all lines from the buffer.
func (b *TerminalBuffer) Clear() {
	b.mu.Lock()
	defer b.mu.Unlock()
	b.lines = b.lines[:0]
	b.partial = ""
}

// Len returns the number of complete lines in the buffer.
func (b *TerminalBuffer) Len() int {
	b.mu.RLock()
	defer b.mu.RUnlock()
	return len(b.lines)
}
