package renderer

import (
	"fmt"
	"testing"

	"gitea.dockr.co/kev/go-jdenticon/internal/engine"
)

// Benchmark optimized PNG renderer vs original FastPNG renderer
func BenchmarkOptimizedPNGToPNG(b *testing.B) {
	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		size := benchmarkSizes[i%len(benchmarkSizes)]
		renderer := NewPNGRenderer(size)

		// Add some shapes
		renderer.SetBackground("#f0f0f0", 1.0)

		for j := 0; j < 3; j++ {
			color := benchmarkColors[j%len(benchmarkColors)]
			points := benchmarkPoints[j%len(benchmarkPoints)]

			renderer.BeginShape(color)
			renderer.AddPolygon(points)
			renderer.EndShape()
		}

		_, err := renderer.ToPNG()
		if err != nil {
			b.Fatalf("ToPNG failed: %v", err)
		}
	}
}

// Benchmark PNG memory usage with different allocation patterns
func BenchmarkPNGMemoryPatterns(b *testing.B) {
	// Shared test data
	testShapes := []struct {
		color  string
		points []engine.Point
	}{
		{"#ff0000", benchmarkPoints[0]},
		{"#00ff00", benchmarkPoints[1]},
		{"#0000ff", benchmarkPoints[2]},
	}

	b.Run("OptimizedPNG", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()

		for i := 0; i < b.N; i++ {
			renderer := NewPNGRenderer(256)
			renderer.SetBackground("#ffffff", 1.0)

			for _, shape := range testShapes {
				renderer.BeginShape(shape.color)
				renderer.AddPolygon(shape.points)
				renderer.EndShape()
			}

			_, err := renderer.ToPNG()
			if err != nil {
				b.Fatalf("ToPNG failed: %v", err)
			}
		}
	})

	b.Run("PNGWrapper", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()

		for i := 0; i < b.N; i++ {
			renderer := NewPNGRenderer(256)
			renderer.SetBackground("#ffffff", 1.0)

			for _, shape := range testShapes {
				renderer.BeginShape(shape.color)
				renderer.AddPolygon(shape.points)
				renderer.EndShape()
			}

			_, err := renderer.ToPNG()
			if err != nil {
				b.Fatalf("ToPNG failed: %v", err)
			}
		}
	})
}

// Benchmark different icon sizes to see memory scaling
func BenchmarkOptimizedPNGSizes(b *testing.B) {
	testShapes := []struct {
		color  string
		points []engine.Point
	}{
		{"#ff0000", benchmarkPoints[0]},
		{"#00ff00", benchmarkPoints[1]},
		{"#0000ff", benchmarkPoints[2]},
	}

	sizes := []int{64, 128, 256, 512}

	for _, size := range sizes {
		b.Run(fmt.Sprintf("Size%d", size), func(b *testing.B) {
			b.ResetTimer()
			b.ReportAllocs()

			for i := 0; i < b.N; i++ {
				renderer := NewPNGRenderer(size)
				renderer.SetBackground("#ffffff", 1.0)

				for _, shape := range testShapes {
					renderer.BeginShape(shape.color)
					renderer.AddPolygon(shape.points)
					renderer.EndShape()
				}

				_, err := renderer.ToPNG()
				if err != nil {
					b.Fatalf("ToPNG failed: %v", err)
				}
			}
		})
	}
}

// Benchmark complex shape rendering with optimized renderer
func BenchmarkOptimizedComplexPNGRendering(b *testing.B) {
	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		renderer := NewPNGRenderer(256)
		renderer.SetBackground("#f8f8f8", 1.0)

		// Render many shapes to simulate complex icon
		for j := 0; j < 12; j++ {
			color := benchmarkColors[j%len(benchmarkColors)]
			points := benchmarkPoints[j%len(benchmarkPoints)]

			renderer.BeginShape(color)
			renderer.AddPolygon(points)
			renderer.EndShape()
		}

		_, err := renderer.ToPNG()
		if err != nil {
			b.Fatalf("ToPNG failed: %v", err)
		}
	}
}

// Benchmark pooling efficiency
func BenchmarkPoolingEfficiency(b *testing.B) {
	b.Run("WithPooling", func(b *testing.B) {
		b.ResetTimer()
		b.ReportAllocs()

		for i := 0; i < b.N; i++ {
			renderer := NewPNGRenderer(128)
			renderer.SetBackground("#ffffff", 1.0)

			// Add multiple polygons to exercise pooling
			for j := 0; j < 10; j++ {
				renderer.BeginShape("#808080")
				renderer.AddPolygon(benchmarkPoints[j%len(benchmarkPoints)])
				renderer.EndShape()
			}

			_, err := renderer.ToPNG()
			if err != nil {
				b.Fatalf("ToPNG failed: %v", err)
			}
		}
	})
}
