//go:build test

package images

import (
	"bytes"
	"testing"
)

// TestValidateImageBytes_JPEG verifies that JPEG magic bytes (FF D8 FF) are detected.
func TestValidateImageBytes_JPEG(t *testing.T) {
	data := []byte{0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01}
	ext, err := ValidateImageBytes(data)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if ext != ".jpg" {
		t.Errorf("expected .jpg, got %q", ext)
	}
}

// TestValidateImageBytes_PNG verifies that PNG magic bytes are detected.
func TestValidateImageBytes_PNG(t *testing.T) {
	data := []byte{0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n', 0x00, 0x00, 0x00, 0x0d}
	ext, err := ValidateImageBytes(data)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if ext != ".png" {
		t.Errorf("expected .png, got %q", ext)
	}
}

// TestValidateImageBytes_GIF87a verifies GIF87a magic bytes are detected.
func TestValidateImageBytes_GIF87a(t *testing.T) {
	data := []byte{'G', 'I', 'F', '8', '7', 'a', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
	ext, err := ValidateImageBytes(data)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if ext != ".gif" {
		t.Errorf("expected .gif, got %q", ext)
	}
}

// TestValidateImageBytes_GIF89a verifies GIF89a magic bytes are detected.
func TestValidateImageBytes_GIF89a(t *testing.T) {
	data := []byte{'G', 'I', 'F', '8', '9', 'a', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
	ext, err := ValidateImageBytes(data)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if ext != ".gif" {
		t.Errorf("expected .gif, got %q", ext)
	}
}

// TestValidateImageBytes_WebP verifies RIFF...WEBP magic bytes are detected.
func TestValidateImageBytes_WebP(t *testing.T) {
	data := []byte{'R', 'I', 'F', 'F', 0x00, 0x00, 0x00, 0x00, 'W', 'E', 'B', 'P'}
	ext, err := ValidateImageBytes(data)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if ext != ".webp" {
		t.Errorf("expected .webp, got %q", ext)
	}
}

// TestValidateImageBytes_AVIF verifies ftypavif magic bytes are detected.
func TestValidateImageBytes_AVIF(t *testing.T) {
	data := []byte{0x00, 0x00, 0x00, 0x20, 'f', 't', 'y', 'p', 'a', 'v', 'i', 'f'}
	ext, err := ValidateImageBytes(data)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if ext != ".avif" {
		t.Errorf("expected .avif, got %q", ext)
	}
}

// TestValidateImageBytes_AVIS verifies ftypavis (AVIF image sequence) magic bytes are detected.
func TestValidateImageBytes_AVIS(t *testing.T) {
	data := []byte{0x00, 0x00, 0x00, 0x20, 'f', 't', 'y', 'p', 'a', 'v', 'i', 's'}
	ext, err := ValidateImageBytes(data)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if ext != ".avif" {
		t.Errorf("expected .avif, got %q", ext)
	}
}

// TestValidateImageBytes_JXL verifies ftypjxl magic bytes are detected.
func TestValidateImageBytes_JXL(t *testing.T) {
	data := []byte{0x00, 0x00, 0x00, 0x0c, 'f', 't', 'y', 'p', 'j', 'x', 'l', ' '}
	ext, err := ValidateImageBytes(data)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if ext != ".jxl" {
		t.Errorf("expected .jxl, got %q", ext)
	}
}

// TestValidateImageBytes_TooSmall verifies that files smaller than 12 bytes are rejected.
func TestValidateImageBytes_TooSmall(t *testing.T) {
	data := []byte{0xff, 0xd8, 0xff}
	_, err := ValidateImageBytes(data)
	if err == nil {
		t.Fatal("expected error for too-small file, got nil")
	}
}

// TestValidateImageBytes_UnknownFormat verifies that unrecognized magic bytes return an error.
func TestValidateImageBytes_UnknownFormat(t *testing.T) {
	data := []byte("this is not an image file at all!!")
	_, err := ValidateImageBytes(data)
	if err == nil {
		t.Fatal("expected error for unknown format, got nil")
	}
}

// TestValidateImageBytes_Exact12Bytes verifies the boundary condition of exactly 12 bytes.
func TestValidateImageBytes_Exact12Bytes(t *testing.T) {
	// Valid JPEG header truncated to exactly 12 bytes (should still match 3-byte magic)
	data := []byte{0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01}
	ext, err := ValidateImageBytes(data)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if ext != ".jpg" {
		t.Errorf("expected .jpg, got %q", ext)
	}
}

// TestValidateImageBytes_WebPNotRIFF verifies that WEBP without RIFF prefix is rejected.
func TestValidateImageBytes_WebPNotRIFF(t *testing.T) {
	data := []byte{'W', 'E', 'B', 'P', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
	_, err := ValidateImageBytes(data)
	if err == nil {
		t.Fatal("expected error for WEBP without RIFF prefix, got nil")
	}
}

// TestValidateImageBytes_AVIFWrongBrand verifies that ftyp with wrong brand is rejected.
func TestValidateImageBytes_AVIFWrongBrand(t *testing.T) {
	// ftyp with "mp41" brand (not avif/avis)
	data := []byte{0x00, 0x00, 0x00, 0x20, 'f', 't', 'y', 'p', 'm', 'p', '4', '1'}
	_, err := ValidateImageBytes(data)
	if err == nil {
		t.Fatal("expected error for non-AVIF ftyp, got nil")
	}
}

// TestValidateImageBytes_Empty verifies that empty input is rejected.
func TestValidateImageBytes_Empty(t *testing.T) {
	data := []byte{}
	_, err := ValidateImageBytes(data)
	if err == nil {
		t.Fatal("expected error for empty input, got nil")
	}
}

// TestValidateImageBytes_AllSupportedFormats verifies every supported format returns a non-empty extension.
func TestValidateImageBytes_AllSupportedFormats(t *testing.T) {
	tests := []struct {
		name    string
		data    []byte
		wantExt string
		wantErr bool
	}{
		{"JPEG", []byte{0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01}, ".jpg", false},
		{"PNG", []byte{0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n', 0, 0, 0, 0}, ".png", false},
		{"GIF87a", []byte{'G', 'I', 'F', '8', '7', 'a', 0, 0, 0, 0, 0, 0}, ".gif", false},
		{"GIF89a", []byte{'G', 'I', 'F', '8', '9', 'a', 0, 0, 0, 0, 0, 0}, ".gif", false},
		{"WebP", []byte{'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P'}, ".webp", false},
		{"AVIF", []byte{0, 0, 0, 0x20, 'f', 't', 'y', 'p', 'a', 'v', 'i', 'f'}, ".avif", false},
		{"AVIS", []byte{0, 0, 0, 0x20, 'f', 't', 'y', 'p', 'a', 'v', 'i', 's'}, ".avif", false},
		{"JXL", []byte{0, 0, 0, 0x0c, 'f', 't', 'y', 'p', 'j', 'x', 'l', ' '}, ".jxl", false},
		{"Random", []byte("not-an-image-file!"), "", true},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			ext, err := ValidateImageBytes(tc.data)
			if tc.wantErr {
				if err == nil {
					t.Errorf("expected error, got nil")
				}
			} else {
				if err != nil {
					t.Fatalf("unexpected error: %v", err)
				}
				if ext != tc.wantExt {
					t.Errorf("expected %q, got %q", tc.wantExt, ext)
				}
			}
		})
	}
}

// TestValidateImageBytes_NoFalsePositiveJPEG verifies that data starting with FF D8 but not FF D8 FF is rejected.
func TestValidateImageBytes_NoFalsePositiveJPEG(t *testing.T) {
	data := []byte{0xff, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
	_, err := ValidateImageBytes(data)
	if err == nil {
		t.Fatal("expected error for non-JPEG starting with FF D8, got nil")
	}
}

// TestValidateImageBytes_PartialMagic verifies that partial magic bytes (e.g., only first 2 bytes of PNG) are rejected.
func TestValidateImageBytes_PartialMagic(t *testing.T) {
	// Only first 2 bytes of PNG signature
	data := []byte{0x89, 'P', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
	_, err := ValidateImageBytes(data)
	if err == nil {
		t.Fatal("expected error for partial PNG magic, got nil")
	}
}

// BenchmarkValidateImageBytes measures validation throughput.
func BenchmarkValidateImageBytes(b *testing.B) {
	data := []byte{0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, _ = ValidateImageBytes(data)
	}
}

// BenchmarkValidateImageBytes_AVIF measures AVIF detection throughput.
func BenchmarkValidateImageBytes_AVIF(b *testing.B) {
	data := []byte{0x00, 0x00, 0x00, 0x20, 'f', 't', 'y', 'p', 'a', 'v', 'i', 'f'}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, _ = ValidateImageBytes(data)
	}
}

// BenchmarkValidateImageBytes_WebP measures WebP detection throughput.
func BenchmarkValidateImageBytes_WebP(b *testing.B) {
	data := []byte{'R', 'I', 'F', 'F', 0x00, 0x00, 0x00, 0x00, 'W', 'E', 'B', 'P'}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, _ = ValidateImageBytes(data)
	}
}

// BenchmarkValidateImageBytes_JXL measures JXL detection throughput.
func BenchmarkValidateImageBytes_JXL(b *testing.B) {
	data := []byte{0x00, 0x00, 0x00, 0x0c, 'f', 't', 'y', 'p', 'j', 'x', 'l', ' '}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, _ = ValidateImageBytes(data)
	}
}

// TestValidateImageBytes_11Bytes verifies that 11-byte files (just under the 12-byte minimum) are rejected.
func TestValidateImageBytes_11Bytes(t *testing.T) {
	data := bytes.Repeat([]byte{0x00}, 11)
	_, err := ValidateImageBytes(data)
	if err == nil {
		t.Fatal("expected error for 11-byte file, got nil")
	}
}
