package jdenticon

import (
	"context"
	"testing"
)

// TestFullWorkflow tests the complete workflow from input to final output
func TestFullWorkflow(t *testing.T) {
	// Test with different input types
	testCases := []struct {
		name  string
		input string
		size  int
	}{
		{"email", "user@example.com", 64},
		{"username", "johndoe", 128},
		{"uuid_like", "550e8400-e29b-41d4-a716-446655440000", 32},
		{"special_chars", "test@#$%^&*()", 96},
		{"unicode", "тест", 64},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			// Test Generate -> ToSVG workflow
			icon, err := Generate(context.Background(), tc.input, tc.size)
			if err != nil {
				t.Fatalf("Generate failed for %s: %v", tc.input, err)
			}

			svg, err := icon.ToSVG()
			if err != nil {
				t.Fatalf("ToSVG failed for %s: %v", tc.input, err)
			}

			if len(svg) == 0 {
				t.Errorf("SVG output empty for %s", tc.input)
			}

			// Test Generate -> ToPNG workflow
			png, err := icon.ToPNG()
			if err != nil {
				t.Fatalf("ToPNG failed for %s: %v", tc.input, err)
			}

			if len(png) == 0 {
				t.Errorf("PNG output empty for %s", tc.input)
			}

			// Verify PNG header
			if len(png) >= 8 {
				pngSignature := []byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}
				for i, expected := range pngSignature {
					if png[i] != expected {
						t.Errorf("Invalid PNG signature for %s at byte %d", tc.input, i)
						break
					}
				}
			}
		})
	}
}

// TestGeneratorCaching tests that the generator properly caches results
func TestGeneratorCaching(t *testing.T) {
	generator, err := NewGeneratorWithCacheSize(10)
	if err != nil {
		t.Fatalf("Failed to create generator: %v", err)
	}

	input := "cache-test"
	size := 64

	// Generate the same icon multiple times
	icon1, err1 := generator.Generate(context.Background(), input, size)
	icon2, err2 := generator.Generate(context.Background(), input, size)

	if err1 != nil || err2 != nil {
		t.Fatalf("Generate failed: err1=%v, err2=%v", err1, err2)
	}

	// Verify they produce the same output
	svg1, err1 := icon1.ToSVG()
	svg2, err2 := icon2.ToSVG()

	if err1 != nil || err2 != nil {
		t.Fatalf("ToSVG failed: err1=%v, err2=%v", err1, err2)
	}

	if svg1 != svg2 {
		t.Error("Cached results differ from fresh generation")
	}
}

// TestCustomConfiguration tests generation with custom configuration
func TestCustomConfiguration(t *testing.T) {
	config := DefaultConfig()
	config.ColorSaturation = 0.8
	config.Padding = 0.15
	config.BackgroundColor = "#ffffff"

	generator, err := NewGeneratorWithConfig(config, 10)
	if err != nil {
		t.Fatalf("Failed to create generator with config: %v", err)
	}

	icon, err := generator.Generate(context.Background(), "config-test", 64)
	if err != nil {
		t.Fatalf("Generate with config failed: %v", err)
	}

	svg, err := icon.ToSVG()
	if err != nil {
		t.Fatalf("ToSVG with config failed: %v", err)
	}

	if len(svg) == 0 {
		t.Error("SVG output empty with custom config")
	}

	// Test convenience function with config
	svg2, err := ToSVGWithConfig(context.Background(), "config-test", 64, config)
	if err != nil {
		t.Fatalf("ToSVGWithConfig failed: %v", err)
	}

	if len(svg2) == 0 {
		t.Error("ToSVGWithConfig output empty")
	}
}

// TestErrorHandling tests various error conditions
func TestErrorHandling(t *testing.T) {
	tests := []struct {
		name     string
		testFunc func() error
		wantErr  bool
	}{
		{
			name: "invalid_cache_size",
			testFunc: func() error {
				_, err := NewGeneratorWithCacheSize(-1)
				return err
			},
			wantErr: true,
		},
		{
			name: "invalid_config_cache_size",
			testFunc: func() error {
				config := DefaultConfig()
				_, err := NewGeneratorWithConfig(config, -1)
				return err
			},
			wantErr: true,
		},
		{
			name: "invalid_config_values",
			testFunc: func() error {
				config := DefaultConfig()
				config.ColorSaturation = 2.0 // Invalid: > 1.0
				_, err := NewGeneratorWithConfig(config, 10)
				return err
			},
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.testFunc()
			if tt.wantErr && err == nil {
				t.Errorf("Expected error for %s, but got none", tt.name)
			}
			if !tt.wantErr && err != nil {
				t.Errorf("Unexpected error for %s: %v", tt.name, err)
			}
		})
	}
}
