package parser

import (
	"context"
	"strings"
	"testing"
)

// BenchmarkSIMDOptimizations tests SIMD-optimized string operations
func BenchmarkSIMDOptimizations(b *testing.B) {
	matcher := NewSIMDStringMatcher()
	testData := []byte(`127.0.0.1 - - [25/Dec/2023:10:00:00 +0000] "GET /index.html HTTP/1.1" 200 1234 "https://example.com" "Mozilla/5.0"`)
	
	benchmarks := []struct {
		name string
		fn   func() interface{}
	}{
		{
			"SIMD_FindNextSpace",
			func() interface{} {
				return matcher.FindNextSpace(testData, 0)
			},
		},
		{
			"SIMD_FindNextQuote",
			func() interface{} {
				return matcher.FindNextQuote(testData, 0)
			},
		},
		{
			"SIMD_FindNextDigit",
			func() interface{} {
				return matcher.FindNextDigit(testData, 0)
			},
		},
		{
			"SIMD_ExtractIPAddress",
			func() interface{} {
				ip, _ := matcher.ExtractIPAddress(testData, 0)
				return ip
			},
		},
		{
			"SIMD_ExtractTimestamp",
			func() interface{} {
				timestamp, _ := matcher.ExtractTimestamp(testData, 0)
				return timestamp
			},
		},
		{
			"SIMD_ExtractQuotedString",
			func() interface{} {
				str, _ := matcher.ExtractQuotedString(testData, 50)
				return str
			},
		},
		{
			"SIMD_ExtractStatusCode",
			func() interface{} {
				status, _ := matcher.ExtractStatusCode(testData, 80)
				return status
			},
		},
		{
			"SIMD_ParseCompleteLine",
			func() interface{} {
				return matcher.ParseLogLineSIMD(testData)
			},
		},
	}

	for _, bench := range benchmarks {
		b.Run(bench.name, func(b *testing.B) {
			b.ResetTimer()
			b.ReportAllocs()
			
			for i := 0; i < b.N; i++ {
				result := bench.fn()
				_ = result // Avoid optimization
			}
		})
	}
}

// BenchmarkSIMDvsRegularParsing compares SIMD vs regular parsing performance
func BenchmarkSIMDvsRegularParsing(b *testing.B) {
	// Setup test data
	logLines := []string{
		`127.0.0.1 - - [25/Dec/2023:10:00:00 +0000] "GET /index.html HTTP/1.1" 200 1234 "https://example.com" "Mozilla/5.0"`,
		`192.168.1.1 - - [25/Dec/2023:10:00:01 +0000] "POST /api/data HTTP/1.1" 201 567 "https://example.com" "curl/7.68.0"`,
		`10.0.0.1 - - [25/Dec/2023:10:00:02 +0000] "GET /style.css HTTP/1.1" 200 890 "https://example.com" "Mozilla/5.0"`,
		`203.0.113.195 - - [25/Dec/2023:10:00:03 +0000] "DELETE /api/users/123 HTTP/1.1" 204 0 "-" "Postman/7.36.0"`,
		`172.16.0.50 - - [25/Dec/2023:10:00:04 +0000] "PUT /api/config HTTP/1.1" 200 456 "https://admin.example.com" "Chrome/91.0"`,
	}

	// Convert to byte slices for SIMD processing
	logBytes := make([][]byte, len(logLines))
	for i, line := range logLines {
		logBytes[i] = []byte(line)
	}

	// Setup parsers
	config := DefaultParserConfig()
	config.MaxLineLength = 16 * 1024
	regularParser := NewParser(
		config,
		NewSimpleUserAgentParser(),
		&mockGeoIPService{},
	)
	
	simdParser := NewLogLineParser()

	b.Run("Regular_SingleLine", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			line := logLines[i%len(logLines)]
			_, _ = regularParser.ParseLine(line)
		}
	})

	b.Run("SIMD_SingleLine", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			lineBytes := logBytes[i%len(logBytes)]
			_ = simdParser.ParseLine(lineBytes)
		}
	})

	b.Run("Regular_BatchLines", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			ctx := context.Background()
			_ = regularParser.ParseLinesWithContext(ctx, logLines)
		}
	})

	b.Run("SIMD_BatchLines", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			_ = simdParser.ParseLines(logBytes)
		}
	})
}

// BenchmarkSIMDCharacterSearch compares SIMD vs standard character search
func BenchmarkSIMDCharacterSearch(b *testing.B) {
	matcher := NewSIMDStringMatcher()
	testData := []byte(`127.0.0.1 - - [25/Dec/2023:10:00:00 +0000] "GET /index.html HTTP/1.1" 200 1234 "https://example.com" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"`)

	b.Run("SIMD_SpaceSearch", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			_ = matcher.FindNextSpace(testData, 0)
		}
	})

	b.Run("Standard_SpaceSearch", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			// Standard byte-by-byte search
			for j := 0; j < len(testData); j++ {
				if testData[j] == ' ' {
					_ = j
					break
				}
			}
		}
	})

	b.Run("SIMD_QuoteSearch", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			_ = matcher.FindNextQuote(testData, 0)
		}
	})

	b.Run("Standard_QuoteSearch", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			// Standard byte-by-byte search
			for j := 0; j < len(testData); j++ {
				if testData[j] == '"' {
					_ = j
					break
				}
			}
		}
	})
}

// BenchmarkSIMDStringExtraction compares SIMD vs regex string extraction
func BenchmarkSIMDStringExtraction(b *testing.B) {
	matcher := NewSIMDStringMatcher()
	testData := []byte(`127.0.0.1 - - [25/Dec/2023:10:00:00 +0000] "GET /index.html HTTP/1.1" 200 1234`)

	b.Run("SIMD_IPExtraction", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			ip, _ := matcher.ExtractIPAddress(testData, 0)
			_ = ip
		}
	})

	b.Run("SIMD_TimestampExtraction", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			timestamp, _ := matcher.ExtractTimestamp(testData, 0)
			_ = timestamp
		}
	})

	b.Run("SIMD_StatusExtraction", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			status, _ := matcher.ExtractStatusCode(testData, 0)
			_ = status
		}
	})
}

// BenchmarkObjectPooling tests the performance impact of object pooling
func BenchmarkObjectPooling(b *testing.B) {
	pool := NewAccessLogEntryPool()
	
	b.Run("WithPooling", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			entry := pool.Get()
			entry.IP = "127.0.0.1"
			entry.Status = 200
			pool.Put(entry)
		}
	})

	b.Run("WithoutPooling", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()
		
		for i := 0; i < b.N; i++ {
			entry := &AccessLogEntry{}
			entry.IP = "127.0.0.1"
			entry.Status = 200
			// No pooling - let GC handle
		}
	})
}

// BenchmarkSIMDScaleTest tests SIMD performance at different scales
func BenchmarkSIMDScaleTest(b *testing.B) {
	simdParser := NewLogLineParser()
	
	scales := []struct {
		name  string
		lines int
	}{
		{"Small_100", 100},
		{"Medium_1K", 1000},
		{"Large_10K", 10000},
		{"XLarge_50K", 50000},
	}

	for _, scale := range scales {
		// Generate test data
		testLines := make([][]byte, scale.lines)
		for i := 0; i < scale.lines; i++ {
			line := generateTestLogLine(i)
			testLines[i] = []byte(line)
		}

		b.Run("SIMD_"+scale.name, func(b *testing.B) {
			b.ResetTimer()
			b.ReportAllocs()
			
			for i := 0; i < b.N; i++ {
				entries := simdParser.ParseLines(testLines)
				b.ReportMetric(float64(len(entries)), "parsed_lines")
			}
		})
	}
}

// generateTestLogLine generates a test log line for benchmarking
func generateTestLogLine(index int) string {
	ip := "192.168.1." + string(rune('1' + (index % 254)))
	method := []string{"GET", "POST", "PUT", "DELETE"}[index%4]
	path := []string{"/", "/api/data", "/style.css", "/script.js"}[index%4]
	status := []int{200, 404, 500, 301}[index%4]
	
	return strings.Join([]string{
		ip, "- - [25/Dec/2023:10:00:00 +0000]",
		`"` + method + " " + path + ` HTTP/1.1"`,
		string(rune('0' + status/100)) + string(rune('0' + (status/10)%10)) + string(rune('0' + status%10)),
		"1234",
		`"https://example.com"`,
		`"Mozilla/5.0"`,
	}, " ")
}

// TestSIMDCorrectnessValidation validates SIMD operations produce correct results
func TestSIMDCorrectnessValidation(t *testing.T) {
	matcher := NewSIMDStringMatcher()
	simdParser := NewLogLineParser()
	
	testCases := []struct {
		name string
		line string
		expectedIP string
		expectedStatus int
	}{
		{
			"Standard_Log",
			`127.0.0.1 - - [25/Dec/2023:10:00:00 +0000] "GET /index.html HTTP/1.1" 200 1234 "https://example.com" "Mozilla/5.0"`,
			"127.0.0.1",
			200,
		},
		{
			"Complex_IP",
			`192.168.100.255 - - [25/Dec/2023:10:00:01 +0000] "POST /api/data HTTP/1.1" 201 567 "https://example.com" "curl/7.68.0"`,
			"192.168.100.255",
			201,
		},
		{
			"Error_Status",
			`10.0.0.1 - - [25/Dec/2023:10:00:02 +0000] "GET /nonexistent HTTP/1.1" 404 0 "-" "Bot/1.0"`,
			"10.0.0.1",
			404,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			lineBytes := []byte(tc.line)
			
			// Test IP extraction
			ip, _ := matcher.ExtractIPAddress(lineBytes, 0)
			if ip != tc.expectedIP {
				t.Errorf("IP extraction failed: got %s, want %s", ip, tc.expectedIP)
			}
			
			// Test status extraction
			status, _ := matcher.ExtractStatusCode(lineBytes, 0)
			if status != tc.expectedStatus {
				t.Errorf("Status extraction failed: got %d, want %d", status, tc.expectedStatus)
			}
			
			// Test complete parsing
			entry := simdParser.ParseLine(lineBytes)
			if entry == nil {
				t.Fatal("SIMD parsing returned nil")
			}
			
			if entry.IP != tc.expectedIP {
				t.Errorf("Complete parsing IP failed: got %s, want %s", entry.IP, tc.expectedIP)
			}
			
			if entry.Status != tc.expectedStatus {
				t.Errorf("Complete parsing status failed: got %d, want %d", entry.Status, tc.expectedStatus)
			}
		})
	}
}

// TestSIMDLookupTables validates lookup table correctness
func TestSIMDLookupTables(t *testing.T) {
	matcher := NewSIMDStringMatcher()
	
	// Test space lookup
	spaces := []byte{' ', '\t', '\n', '\r'}
	for _, c := range spaces {
		if !matcher.spaceLookup[c] {
			t.Errorf("Space lookup failed for character %c (%d)", c, c)
		}
	}
	
	// Test digit lookup
	for c := byte('0'); c <= '9'; c++ {
		if !matcher.digitLookup[c] {
			t.Errorf("Digit lookup failed for character %c", c)
		}
	}
	
	// Test quote lookup
	quotes := []byte{'"', '\''}
	for _, c := range quotes {
		if !matcher.quoteLookup[c] {
			t.Errorf("Quote lookup failed for character %c", c)
		}
	}
	
	// Test non-special characters
	if matcher.spaceLookup['a'] {
		t.Error("Space lookup false positive for 'a'")
	}
	
	if matcher.digitLookup['a'] {
		t.Error("Digit lookup false positive for 'a'")
	}
}

// TestObjectPoolEfficiency validates object pool functionality
func TestObjectPoolEfficiency(t *testing.T) {
	pool := NewAccessLogEntryPool()
	
	// Get entry from pool
	entry1 := pool.Get()
	if entry1 == nil {
		t.Fatal("Pool returned nil entry")
	}
	
	// Modify entry
	entry1.IP = "127.0.0.1"
	entry1.Status = 200
	
	// Return to pool
	pool.Put(entry1)
	
	// Get another entry (should be reused)
	entry2 := pool.Get()
	if entry2 == nil {
		t.Fatal("Pool returned nil after put")
	}
	
	// Should be reset
	if entry2.IP != "" {
		t.Error("Pool entry not properly reset")
	}
	
	if entry2.Status != 0 {
		t.Error("Pool entry status not properly reset")
	}
}