package imageutils

import (
	"image"
	"image/color"
	"math"
)

type ImageAnalyzer struct {
	image.Image
}

// Calculate the energy using the dual-gradient energy function
func getEnergy(
	firstPixel color.Color,
	secondPixel color.Color,
) float64 {
	firstRed, firstGreen, firstBlue, _ := firstPixel.RGBA()
	firstRed, firstGreen, firstBlue = firstRed>>8, firstGreen>>8, firstBlue>>8
	secondRed, secondGreen, secondBlue, _ := secondPixel.RGBA()
	secondRed, secondGreen, secondBlue = secondRed>>8, secondGreen>>8, secondBlue>>8

	return float64(
		math.Abs(float64(firstRed-secondRed)) +
			math.Abs(float64(firstGreen-secondGreen)) +
			math.Abs(float64(firstBlue-secondBlue)),
	)
}

// Calculate a 0-255 grayscale value from a color using the NTSC formula
func colorToGray(color color.Color) float64 {
	red, green, blue, _ := color.RGBA()
	red, green, blue = red>>8, green>>8, blue>>8

	return 0.299*float64(red) +
		0.587*float64(green) +
		0.114*float64(blue)
}

func sumSlice(slice []float64) float64 {
	var sum float64
	for _, value := range slice {
		sum += value
	}
	return sum
}

func (image *ImageAnalyzer) CalculateEnergyAt(x int, y int) float64 {
	northPixel := image.At(
		x,
		max(0, y-1),
	)
	northEastPixel := image.At(
		min(image.Bounds().Max.X, x+1),
		max(0, y-1),
	)
	eastPixel := image.At(
		min(image.Bounds().Max.X, x+1),
		y,
	)
	southEastPixel := image.At(
		min(image.Bounds().Max.X, x+1),
		min(image.Bounds().Max.Y, y+1),
	)
	southPixel := image.At(
		x,
		min(image.Bounds().Max.Y, y+1),
	)
	southWestPixel := image.At(
		max(0, x-1),
		min(image.Bounds().Max.Y, y+1),
	)
	westPixel := image.At(
		max(0, x-1),
		y,
	)
	northWestPixel := image.At(
		max(0, x-1),
		max(0, y-1),
	)

	thisPixel := image.At(
		x,
		y,
	)

	_ = thisPixel
	_ = northPixel
	_ = northEastPixel
	_ = southPixel

	horizontalMatrix := []float64{
		colorToGray(northWestPixel), 0, -colorToGray(northEastPixel),
		2 * colorToGray(westPixel), 0, -2 * colorToGray(eastPixel),
		colorToGray(southWestPixel), 0, -colorToGray(southEastPixel),
	}
	verticalMatrix := []float64{
		colorToGray(northWestPixel), 2 * colorToGray(northPixel), colorToGray(northEastPixel),
		0, 0, 0,
		-colorToGray(southWestPixel), -2 * colorToGray(southPixel), -colorToGray(southEastPixel),
	}

	g_x := sumSlice(horizontalMatrix)
	g_y := sumSlice(verticalMatrix)

	return math.Sqrt(
		math.Pow(g_x, 2) +
			math.Pow(g_y, 2),
	)
}
