package ui

import (
	"image"
	"image/color"

	"opslag.de/schobers/geom"
)

type AlphaPixelImageSource struct {
	ImageAlphaPixelTestFn

	Size geom.Point
}

func (s *AlphaPixelImageSource) CreateImage() (image.Image, error) {
	return DrawImageAlpha(s.Size, s.ImageAlphaPixelTestFn), nil
}

type ImageAlphaPixelTestFn func(geom.PointF32) uint8

func (f ImageAlphaPixelTestFn) CreateImageSource(size geom.Point) ImageSource {
	return &AlphaPixelImageSource{f, size}
}

type ImagePixelTestFn func(geom.PointF32) bool

func (f ImagePixelTestFn) CreateImageSource(size geom.Point) ImageSource {
	return &PixelImageSource{f, size}
}

func createTexture(ctx Context, source ImageSource) Texture {
	texture, err := ctx.Renderer().CreateTexture(source)
	if err != nil {
		return nil
	}
	return texture
}

func CreateIcon(ctx Context, test ImagePixelTestFn) Texture {
	return createTexture(ctx, test.CreateImageSource(IconSize()))
}

func CreateTexture(ctx Context, size geom.Point, test ImagePixelTestFn) Texture {
	return createTexture(ctx, test.CreateImageSource(size))
}

func CreateTextureAlpha(ctx Context, size geom.Point, test ImageAlphaPixelTestFn) Texture {
	return createTexture(ctx, test.CreateImageSource(size))
}

func DrawIcon(test ImagePixelTestFn) image.Image {
	size := IconSize()
	return DrawImage(size, test)
}

func DrawImage(size geom.Point, test ImagePixelTestFn) image.Image {
	r := image.Rect(0, 0, size.X, size.Y)
	icon := image.NewRGBA(r)
	for y := 0; y < size.Y; y++ {
		for x := 0; x < size.X; x++ {
			pt := geom.PtF32(float32(x), float32(y))
			if test(pt) {
				icon.Set(x, y, color.White)
			}
		}
	}
	return icon
}

func DrawImageAlpha(size geom.Point, test ImageAlphaPixelTestFn) image.Image {
	r := image.Rect(0, 0, size.X, size.Y)
	icon := image.NewAlpha(r)
	for y := 0; y < size.Y; y++ {
		for x := 0; x < size.X; x++ {
			pt := geom.PtF32(float32(x), float32(y))
			if a := test(pt); a > 0 {
				icon.Set(x, y, color.Alpha{A: a})
			}
		}
	}
	return icon
}

func GetOrCreateIcon(ctx Context, name string, test ImagePixelTestFn) Texture {
	texture := ctx.Textures().Texture(name)
	if texture != nil {
		return texture
	}
	texture, err := ctx.Textures().CreateTexture(name, test.CreateImageSource(IconSize()))
	if err != nil {
		return nil
	}
	return texture
}

func IconSize() geom.Point {
	return geom.Pt(448, 512)
}

type PixelImageSource struct {
	ImagePixelTestFn

	Size geom.Point
}

func (s *PixelImageSource) CreateImage() (image.Image, error) {
	return DrawImage(s.Size, s.ImagePixelTestFn), nil
}