package engine

import (
	"image/color"
	"testing"
)

func TestParseHexColorToRGBA(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected color.RGBA
		hasError bool
	}{
		// Valid cases
		{"RGB short form", "#000", color.RGBA{0, 0, 0, 255}, false},
		{"RGB short form white", "#fff", color.RGBA{255, 255, 255, 255}, false},
		{"RGB short form mixed", "#f0a", color.RGBA{255, 0, 170, 255}, false},
		{"RGBA short form", "#f0a8", color.RGBA{255, 0, 170, 136}, false},
		{"RRGGBB full form", "#000000", color.RGBA{0, 0, 0, 255}, false},
		{"RRGGBB full form white", "#ffffff", color.RGBA{255, 255, 255, 255}, false},
		{"RRGGBB full form mixed", "#ff00aa", color.RGBA{255, 0, 170, 255}, false},
		{"RRGGBBAA full form", "#ff00aa80", color.RGBA{255, 0, 170, 128}, false},
		{"RRGGBBAA full form transparent", "#ff00aa00", color.RGBA{255, 0, 170, 0}, false},
		{"RRGGBBAA full form opaque", "#ff00aaff", color.RGBA{255, 0, 170, 255}, false},

		// Invalid cases
		{"Empty string", "", color.RGBA{}, true},
		{"No hash prefix", "ffffff", color.RGBA{}, true},
		{"Invalid length", "#12", color.RGBA{}, true},
		{"Invalid length", "#12345", color.RGBA{}, true},
		{"Invalid length", "#1234567", color.RGBA{}, true},
		{"Invalid hex character", "#gggggg", color.RGBA{}, true},
		{"Invalid hex character short", "#ggg", color.RGBA{}, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := ParseHexColorToRGBA(tt.input)

			if tt.hasError {
				if err == nil {
					t.Errorf("ParseHexColorToRGBA(%q) expected error, got nil", tt.input)
				}
				return
			}

			if err != nil {
				t.Errorf("ParseHexColorToRGBA(%q) unexpected error: %v", tt.input, err)
				return
			}

			if result != tt.expected {
				t.Errorf("ParseHexColorToRGBA(%q) = %+v, expected %+v", tt.input, result, tt.expected)
			}
		})
	}
}

func TestValidateHexColor(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		hasError bool
	}{
		// Valid cases
		{"RGB short", "#000", false},
		{"RGB short uppercase", "#FFF", false},
		{"RGB short mixed case", "#f0A", false},
		{"RGBA short", "#f0a8", false},
		{"RRGGBB", "#000000", false},
		{"RRGGBB uppercase", "#FFFFFF", false},
		{"RRGGBB mixed case", "#Ff00Aa", false},
		{"RRGGBBAA", "#ff00aa80", false},
		{"RRGGBBAA uppercase", "#FF00AA80", false},

		// Invalid cases
		{"Empty string", "", true},
		{"No hash", "ffffff", true},
		{"Too short", "#12", true},
		{"Invalid length", "#12345", true},
		{"Too long", "#123456789", true},
		{"Invalid character", "#gggggg", true},
		{"Invalid character short", "#ggg", true},
		{"Space", "#fff fff", true},
		{"Special character", "#fff@ff", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateHexColor(tt.input)

			if tt.hasError && err == nil {
				t.Errorf("ValidateHexColor(%q) expected error, got nil", tt.input)
			} else if !tt.hasError && err != nil {
				t.Errorf("ValidateHexColor(%q) unexpected error: %v", tt.input, err)
			}
		})
	}
}

func TestParseHexColorToEngine(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected Color
		hasError bool
	}{
		{"RGB short", "#000", NewColorRGBA(0, 0, 0, 255), false},
		{"RGB short white", "#fff", NewColorRGBA(255, 255, 255, 255), false},
		{"RRGGBB", "#ff00aa", NewColorRGBA(255, 0, 170, 255), false},
		{"RRGGBBAA", "#ff00aa80", NewColorRGBA(255, 0, 170, 128), false},
		{"Invalid", "#invalid", Color{}, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := ParseHexColorToEngine(tt.input)

			if tt.hasError {
				if err == nil {
					t.Errorf("ParseHexColorToEngine(%q) expected error, got nil", tt.input)
				}
				return
			}

			if err != nil {
				t.Errorf("ParseHexColorToEngine(%q) unexpected error: %v", tt.input, err)
				return
			}

			resultR, resultG, resultB, err1 := result.ToRGB()
			if err1 != nil {
				t.Fatalf("result.ToRGB failed: %v", err1)
			}
			expectedR, expectedG, expectedB, err2 := tt.expected.ToRGB()
			if err2 != nil {
				t.Fatalf("expected.ToRGB failed: %v", err2)
			}
			if resultR != expectedR || resultG != expectedG ||
				resultB != expectedB || result.A != tt.expected.A {
				t.Errorf("ParseHexColorToEngine(%q) = R:%d G:%d B:%d A:%d, expected R:%d G:%d B:%d A:%d",
					tt.input, resultR, resultG, resultB, result.A,
					expectedR, expectedG, expectedB, tt.expected.A)
			}
		})
	}
}

func TestParseHexColorForRenderer(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		opacity  float64
		expected color.RGBA
		hasError bool
	}{
		{"RGB with opacity 1.0", "#ff0000", 1.0, color.RGBA{255, 0, 0, 255}, false},
		{"RGB with opacity 0.5", "#ff0000", 0.5, color.RGBA{255, 0, 0, 127}, false},
		{"RGB with opacity 0.0", "#ff0000", 0.0, color.RGBA{255, 0, 0, 0}, false},
		{"RGBA with opacity 1.0", "#ff000080", 1.0, color.RGBA{255, 0, 0, 128}, false},
		{"RGBA with opacity 0.5", "#ff000080", 0.5, color.RGBA{255, 0, 0, 64}, false},
		{"Invalid color", "#invalid", 1.0, color.RGBA{}, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := ParseHexColorForRenderer(tt.input, tt.opacity)

			if tt.hasError {
				if err == nil {
					t.Errorf("ParseHexColorForRenderer(%q, %f) expected error, got nil", tt.input, tt.opacity)
				}
				return
			}

			if err != nil {
				t.Errorf("ParseHexColorForRenderer(%q, %f) unexpected error: %v", tt.input, tt.opacity, err)
				return
			}

			if result != tt.expected {
				t.Errorf("ParseHexColorForRenderer(%q, %f) = %+v, expected %+v", tt.input, tt.opacity, result, tt.expected)
			}
		})
	}
}

func TestHexToByte(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected uint8
		hasError bool
	}{
		{"Zero", "00", 0, false},
		{"Max", "ff", 255, false},
		{"Max uppercase", "FF", 255, false},
		{"Mixed case", "Ff", 255, false},
		{"Middle value", "80", 128, false},
		{"Small value", "0a", 10, false},
		{"Invalid length short", "f", 0, true},
		{"Invalid length long", "fff", 0, true},
		{"Invalid character", "gg", 0, true},
		{"Empty string", "", 0, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := hexToByte(tt.input)

			if tt.hasError {
				if err == nil {
					t.Errorf("hexToByte(%q) expected error, got nil", tt.input)
				}
				return
			}

			if err != nil {
				t.Errorf("hexToByte(%q) unexpected error: %v", tt.input, err)
				return
			}

			if result != tt.expected {
				t.Errorf("hexToByte(%q) = %d, expected %d", tt.input, result, tt.expected)
			}
		})
	}
}
