package service

import (
	"bytes"
	"errors"
	"image"
	"image/color"
	"image/png"
	"testing"
)

func avatarPNG(t *testing.T, width, height int) []byte {
	t.Helper()
	img := image.NewNRGBA(image.Rect(0, 0, width, height))
	for y := 0; y < height; y++ {
		for x := 0; x < width; x++ {
			img.Set(x, y, color.NRGBA{R: uint8(x), G: uint8(y), B: 128, A: 255})
		}
	}
	var out bytes.Buffer
	if err := png.Encode(&out, img); err != nil {
		t.Fatalf("encode png: %v", err)
	}
	return out.Bytes()
}

func TestNormalizeAvatar(t *testing.T) {
	input := avatarPNG(t, 900, 300)
	normalized, err := NormalizeAvatar(input)
	if err != nil {
		t.Fatalf("NormalizeAvatar: %v", err)
	}
	config, format, err := image.DecodeConfig(bytes.NewReader(normalized))
	if err != nil {
		t.Fatalf("DecodeConfig: %v", err)
	}
	if format != "png" {
		t.Fatalf("format = %q, want png", format)
	}
	if config.Width != avatarNormalizedDimension || config.Height != 170 {
		t.Fatalf("normalized dimensions = %dx%d, want 512x170", config.Width, config.Height)
	}
}

func TestNormalizeAvatarRejectsInvalidAndOversizedInputs(t *testing.T) {
	if _, err := NormalizeAvatar([]byte("not an image")); !isAvatarError(err, ErrAvatarInvalid) {
		t.Fatalf("invalid image error = %v, want ErrAvatarInvalid", err)
	}
	if _, err := NormalizeAvatar(make([]byte, AvatarMaxUploadBytes+1)); !isAvatarError(err, ErrAvatarTooLarge) {
		t.Fatalf("oversized image error = %v, want ErrAvatarTooLarge", err)
	}
	if _, err := NormalizeAvatar(avatarPNG(t, AvatarMaxSourceDimension+1, 1)); !isAvatarError(err, ErrAvatarInvalid) {
		t.Fatalf("oversized dimensions error = %v, want ErrAvatarInvalid", err)
	}
}

func TestGeneratedAvatarIsStableAndVersioned(t *testing.T) {
	first := generatedAvatar("hazel", 3)
	second := generatedAvatar("hazel", 3)
	if first.ContentType != "image/png" || !first.Generated {
		t.Fatalf("generated avatar metadata = %#v", first)
	}
	if !bytes.Equal(first.Content, second.Content) {
		t.Fatal("generated avatar changed for the same login")
	}
	if first.Version != 3 {
		t.Fatalf("version = %d, want 3", first.Version)
	}
	decoded, _, err := image.Decode(bytes.NewReader(first.Content))
	if err != nil {
		t.Fatalf("decode generated avatar: %v", err)
	}
	if got := color.NRGBAModel.Convert(decoded.At(15, 15)).(color.NRGBA); got.A != 255 {
		t.Fatalf("generated avatar background alpha = %d, want opaque", got.A)
	}
}

func isAvatarError(err, target error) bool {
	return errors.Is(err, target)
}
