package utils

import (
	"testing"
)

func TestL4Colormap_ControlPoints(t *testing.T) {
	tests := []struct {
		idx   int
		wantR uint8
		wantG uint8
		wantB uint8
		desc  string
	}{
		{0, 0, 0, 0, "black at index 0"},
		{255, 255, 255, 0, "yellow at index 255"},
	}
	for _, tt := range tests {
		pixel := L4Colormap[tt.idx]
		if pixel.R != tt.wantR || pixel.G != tt.wantG || pixel.B != tt.wantB {
			t.Errorf("L4Colormap[%d] (%s): got (%d,%d,%d), want (%d,%d,%d)",
				tt.idx, tt.desc, pixel.R, pixel.G, pixel.B, tt.wantR, tt.wantG, tt.wantB)
		}
	}

	// Index 85: first segment is (0,0,0)→(0.85,0,0), t=85/85=1.0
	p85 := L4Colormap[85]
	if p85.R != 216 || p85.G != 0 || p85.B != 0 {
		t.Errorf("L4Colormap[85]: got (%d,%d,%d), want dark red", p85.R, p85.G, p85.B)
	}

	// Index 170: second segment is (0.85,0,0)→(1.0,0.15,0), t=85/85=1.0
	p170 := L4Colormap[170]
	if p170.R != 255 || p170.G != 38 || p170.B != 0 {
		t.Errorf("L4Colormap[170]: got (%d,%d,%d), want orange-red", p170.R, p170.G, p170.B)
	}
}

func TestL4Colormap_MonotonicRed(t *testing.T) {
	// Red channel should be non-decreasing (black→red→orange→yellow)
	for i := 1; i < 256; i++ {
		if L4Colormap[i].R < L4Colormap[i-1].R {
			t.Errorf("R decreased at index %d: %d%d", i-1, L4Colormap[i-1].R, L4Colormap[i].R)
		}
	}
}

func TestL4Colormap_GreenZeroThenIncreasing(t *testing.T) {
	// Green is 0 in the first segment (indices 0-85), then increases
	for i := 0; i <= 85; i++ {
		if L4Colormap[i].G != 0 {
			t.Errorf("G should be 0 at index %d, got %d", i, L4Colormap[i].G)
		}
	}
	// Green should be non-decreasing after index 85
	for i := 86; i < 256; i++ {
		if L4Colormap[i].G < L4Colormap[i-1].G {
			t.Errorf("G decreased at index %d: %d%d", i-1, L4Colormap[i-1].G, L4Colormap[i].G)
		}
	}
}

func TestL4Colormap_BlueAlwaysZero(t *testing.T) {
	for i := range 256 {
		if L4Colormap[i].B != 0 {
			t.Errorf("B should be 0 at index %d, got %d", i, L4Colormap[i].B)
		}
	}
}

func TestApplyL4Colormap_Basic(t *testing.T) {
	gray := [][]uint8{
		{0, 128, 255},
	}
	result := ApplyL4Colormap(gray)
	if len(result) != 1 || len(result[0]) != 3 {
		t.Fatalf("shape mismatch: got %dx%d", len(result), len(result[0]))
	}

	// Index 0 → black
	if result[0][0] != (RGBPixel{0, 0, 0}) {
		t.Errorf("pixel 0: got %v, want black", result[0][0])
	}
	// Index 255 → yellow
	if result[0][2] != (RGBPixel{255, 255, 0}) {
		t.Errorf("pixel 255: got %v, want yellow", result[0][2])
	}
	// Index 128 → should be a valid colormap entry (just check it matches the table)
	if result[0][1] != L4Colormap[128] {
		t.Errorf("pixel 128: got %v, want %v", result[0][1], L4Colormap[128])
	}
}

func TestApplyL4Colormap_MultiRow(t *testing.T) {
	gray := [][]uint8{
		{0, 255},
		{255, 0},
	}
	result := ApplyL4Colormap(gray)
	if len(result) != 2 || len(result[0]) != 2 {
		t.Fatalf("shape mismatch: got %dx%d", len(result), len(result[0]))
	}
	if result[0][0] != L4Colormap[0] {
		t.Errorf("(0,0): got %v, want %v", result[0][0], L4Colormap[0])
	}
	if result[1][1] != L4Colormap[0] {
		t.Errorf("(1,1): got %v, want %v", result[1][1], L4Colormap[0])
	}
}

func TestApplyL4Colormap_Empty(t *testing.T) {
	tests := []struct {
		name string
		data [][]uint8
	}{
		{"nil", nil},
		{"empty outer", [][]uint8{}},
		{"empty inner", [][]uint8{{}}},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := ApplyL4Colormap(tt.data)
			if result != nil {
				t.Errorf("expected nil for %s, got %v", tt.name, result)
			}
		})
	}
}