// Package main demonstrates concurrent usage patterns for the go-jdenticon library.
// This example shows safe and efficient ways to generate identicons from multiple goroutines.
package main

import (
	"context"
	"fmt"
	"log"
	"sync"
	"time"

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

func main() {
	fmt.Println("Go Jdenticon - Concurrent Usage Examples")
	fmt.Println("========================================")

	// Example 1: Using package-level functions (simplest)
	fmt.Println("\n1. Package-level functions (uses singleton generator)")
	demonstratePackageLevelConcurrency()

	// Example 2: Shared generator instance (recommended for performance)
	fmt.Println("\n2. Shared generator instance (optimal performance)")
	demonstrateSharedGenerator()

	// Example 3: Cache performance monitoring
	fmt.Println("\n3. Cache performance monitoring")
	demonstrateCacheMonitoring()

	// Example 4: High-throughput concurrent generation
	fmt.Println("\n4. High-throughput concurrent generation")
	demonstrateHighThroughput()
}

// demonstratePackageLevelConcurrency shows the simplest concurrent usage pattern
func demonstratePackageLevelConcurrency() {
	userEmails := []string{
		"alice@example.com",
		"bob@example.com",
		"charlie@example.com",
		"diana@example.com",
		"eve@example.com",
	}

	var wg sync.WaitGroup

	for i, email := range userEmails {
		wg.Add(1)
		go func(id int, userEmail string) {
			defer wg.Done()

			// Safe: Package-level functions use internal singleton
			icon, err := jdenticon.Generate(context.Background(), userEmail, 64)
			if err != nil {
				log.Printf("Worker %d failed to generate icon: %v", id, err)
				return
			}

			// Icons are immutable and safe to use concurrently
			svg, err := icon.ToSVG()
			if err != nil {
				log.Printf("Worker %d failed to generate SVG: %v", id, err)
				return
			}

			fmt.Printf("  Worker %d: Generated %d-byte SVG for %s\n",
				id, len(svg), userEmail)
		}(i, email)
	}

	wg.Wait()
	fmt.Println("  ✓ All workers completed successfully")
}

// demonstrateSharedGenerator shows optimal performance pattern with shared generator
func demonstrateSharedGenerator() {
	// Create custom configuration
	config, err := jdenticon.Configure(
		jdenticon.WithColorSaturation(0.8),
		jdenticon.WithPadding(0.1),
		jdenticon.WithHueRestrictions([]float64{120, 180, 240}), // Blue/green theme
	)
	if err != nil {
		log.Fatalf("Failed to create config: %v", err)
	}

	// Create generator with larger cache for concurrent workload
	generator, err := jdenticon.NewGeneratorWithConfig(config, 1000)
	if err != nil {
		log.Fatalf("Failed to create generator: %v", err)
	}

	const numWorkers = 10
	const iconsPerWorker = 5

	var wg sync.WaitGroup
	start := time.Now()

	for workerID := 0; workerID < numWorkers; workerID++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()

			for i := 0; i < iconsPerWorker; i++ {
				userID := fmt.Sprintf("user-%d-%d@company.com", id, i)

				// Safe: Multiple goroutines can use the same generator
				icon, err := generator.Generate(context.Background(), userID, 96)
				if err != nil {
					log.Printf("Worker %d failed to generate icon %d: %v", id, i, err)
					continue
				}

				// Generate both formats concurrently on the same icon
				var pngData []byte
				var svgData string
				var formatWg sync.WaitGroup

				formatWg.Add(2)
				go func() {
					defer formatWg.Done()
					pngData, _ = icon.ToPNG()
				}()
				go func() {
					defer formatWg.Done()
					svgData, _ = icon.ToSVG()
				}()
				formatWg.Wait()

				fmt.Printf("  Worker %d: Generated PNG (%d bytes) and SVG (%d bytes) for %s\n",
					id, len(pngData), len(svgData), userID)
			}
		}(workerID)
	}

	wg.Wait()
	duration := time.Since(start)
	totalIcons := numWorkers * iconsPerWorker

	fmt.Printf("  ✓ Generated %d icons in %v (%.0f icons/sec)\n",
		totalIcons, duration, float64(totalIcons)/duration.Seconds())
}

// demonstrateCacheMonitoring shows how to monitor cache performance
func demonstrateCacheMonitoring() {
	generator, err := jdenticon.NewGeneratorWithConfig(jdenticon.DefaultConfig(), 100)
	if err != nil {
		log.Fatalf("Failed to create generator: %v", err)
	}

	// Generate some icons to populate cache
	testUsers := []string{
		"user1@test.com", "user2@test.com", "user3@test.com",
		"user4@test.com", "user5@test.com",
	}

	var wg sync.WaitGroup

	// First pass: populate cache
	fmt.Println("  Populating cache...")
	for _, user := range testUsers {
		wg.Add(1)
		go func(u string) {
			defer wg.Done()
			_, _ = generator.Generate(context.Background(), u, 64)
		}(user)
	}
	wg.Wait()

	hits1, misses1 := generator.GetCacheMetrics()
	fmt.Printf("  After first pass - Hits: %d, Misses: %d\n", hits1, misses1)

	// Second pass: should hit cache
	fmt.Println("  Requesting same icons (should hit cache)...")
	for _, user := range testUsers {
		wg.Add(1)
		go func(u string) {
			defer wg.Done()
			_, _ = generator.Generate(context.Background(), u, 64)
		}(user)
	}
	wg.Wait()

	hits2, misses2 := generator.GetCacheMetrics()
	fmt.Printf("  After second pass - Hits: %d, Misses: %d\n", hits2, misses2)

	if hits2 > hits1 {
		ratio := float64(hits2) / float64(hits2+misses2) * 100
		fmt.Printf("  ✓ Cache hit ratio: %.1f%%\n", ratio)
	}
}

// demonstrateHighThroughput shows high-performance concurrent generation
func demonstrateHighThroughput() {
	generator, err := jdenticon.NewGeneratorWithConfig(jdenticon.DefaultConfig(), 2000)
	if err != nil {
		log.Fatalf("Failed to create generator: %v", err)
	}

	const numWorkers = 20
	const duration = 2 * time.Second

	var wg sync.WaitGroup
	stopChan := make(chan struct{})

	// Start timer
	go func() {
		time.Sleep(duration)
		close(stopChan)
	}()

	start := time.Now()

	// Launch workers
	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go func(workerID int) {
			defer wg.Done()

			count := 0
			for {
				select {
				case <-stopChan:
					fmt.Printf("  Worker %d generated %d icons\n", workerID, count)
					return
				default:
					userID := fmt.Sprintf("load-test-user-%d-%d", workerID, count)
					_, err := generator.Generate(context.Background(), userID, 32)
					if err != nil {
						log.Printf("Generation failed: %v", err)
						continue
					}
					count++
				}
			}
		}(i)
	}

	wg.Wait()
	actualDuration := time.Since(start)

	hits, misses := generator.GetCacheMetrics()
	total := hits + misses
	throughput := float64(total) / actualDuration.Seconds()

	fmt.Printf("  ✓ Generated %d icons in %v (%.0f icons/sec)\n",
		total, actualDuration, throughput)
	fmt.Printf("  ✓ Cache performance - Hits: %d, Misses: %d (%.1f%% hit rate)\n",
		hits, misses, float64(hits)/float64(total)*100)
}
