package accesslog

import (
	"fmt"
	"strings"
	"testing"
)

func TestBackScanner(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected []string
	}{
		{
			name:     "empty file",
			input:    "",
			expected: []string{},
		},
		{
			name:     "single line without newline",
			input:    "single line",
			expected: []string{"single line"},
		},
		{
			name:     "single line with newline",
			input:    "single line\n",
			expected: []string{"single line"},
		},
		{
			name:     "multiple lines",
			input:    "first\nsecond\nthird\n",
			expected: []string{"third", "second", "first"},
		},
		{
			name:     "multiple lines without final newline",
			input:    "first\nsecond\nthird",
			expected: []string{"third", "second", "first"},
		},
		{
			name:     "lines longer than chunk size",
			input:    "short\n" + strings.Repeat("a", 20) + "\nshort\n",
			expected: []string{"short", strings.Repeat("a", 20), "short"},
		},
		{
			name:     "empty lines",
			input:    "first\n\n\nlast\n",
			expected: []string{"last", "first"},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Setup mock file
			mockFile := &MockFile{}
			_, err := mockFile.Write([]byte(tt.input))
			if err != nil {
				t.Fatalf("failed to write to mock file: %v", err)
			}

			// Create scanner with small chunk size to test chunking
			scanner := NewBackScanner(mockFile, 10)

			// Collect all lines
			var lines [][]byte
			for scanner.Scan() {
				lines = append(lines, scanner.Bytes())
			}

			// Check for scanning errors
			if err := scanner.Err(); err != nil {
				t.Errorf("scanner error: %v", err)
			}

			// Compare results
			if len(lines) != len(tt.expected) {
				t.Errorf("got %d lines, want %d lines", len(lines), len(tt.expected))
				return
			}

			for i, line := range lines {
				if string(line) != tt.expected[i] {
					t.Errorf("line %d: got %q, want %q", i, line, tt.expected[i])
				}
			}
		})
	}
}

func TestBackScannerWithVaryingChunkSizes(t *testing.T) {
	input := "first\nsecond\nthird\nfourth\nfifth\n"
	expected := []string{"fifth", "fourth", "third", "second", "first"}
	chunkSizes := []int{1, 2, 3, 5, 10, 20, 100}

	for _, chunkSize := range chunkSizes {
		t.Run(fmt.Sprintf("chunk_size_%d", chunkSize), func(t *testing.T) {
			mockFile := &MockFile{}
			_, err := mockFile.Write([]byte(input))
			if err != nil {
				t.Fatalf("failed to write to mock file: %v", err)
			}

			scanner := NewBackScanner(mockFile, chunkSize)

			var lines [][]byte
			for scanner.Scan() {
				lines = append(lines, scanner.Bytes())
			}

			if err := scanner.Err(); err != nil {
				t.Errorf("scanner error: %v", err)
			}

			if len(lines) != len(expected) {
				t.Errorf("got %d lines, want %d lines", len(lines), len(expected))
				return
			}

			for i, line := range lines {
				if string(line) != expected[i] {
					t.Errorf("chunk size %d, line %d: got %q, want %q",
						chunkSize, i, line, expected[i])
				}
			}
		})
	}
}