package main

import (
	"fmt"
	sg "github.com/d2fn/sumi/internal/graphics"
	rl "github.com/gen2brain/raylib-go/raylib"
	"github.com/ojrac/opensimplex-go"
	"math"
)

type Field interface {
	/**
	 * return a value on the range 0,1
	 */
	Get(x float32, y float32) float32
}

// TRANSFORM FIELDS
type ScaleField struct {
	field Field
	scale float32
}

func (f *ScaleField) Get(x, y float32) float32 {
	return f.field.Get(x/f.scale, y/f.scale)
}

type TranslateField struct {
	field Field
	x, y  float32
}

func (f TranslateField) Get(x float32, y float32) float32 {
	return f.field.Get(x+f.x, y+f.y)
}

// NOISE FIELDS

type SimplexNoiseField struct {
	Noise opensimplex.Noise32
}

func (f *SimplexNoiseField) Get(x, y float32) float32 {
	return f.Noise.Eval2(x, y)
}

// IMAGE FIELDS

type ImageField struct {
	image            *rl.Image
	pixels           ImagePixels
	offsetX, offsetY int
}

type ImagePixels struct {
	w, h   int
	colors []rl.Color
}

func (p *ImagePixels) Get(x, y int) rl.Color {
	if x < 0 || x >= p.w {
		return rl.Black
	}
	if y < 0 || y >= p.h {
		return rl.Black
	}
	return p.colors[x+y*p.w]
}

func NewImageField(path string) *ImageField {
	image := rl.LoadImage(path)
	fmt.Printf("loaded image from %s\n", path)
	colors := rl.LoadImageColors(image)
	pixels := ImagePixels{
		w:      int(image.Width),
		h:      int(image.Height),
		colors: colors,
	}
	offsetX := int(image.Width) / 2
	offsetY := int(image.Height) / 2
	return &ImageField{
		image:   image,
		pixels:  pixels,
		offsetX: offsetX,
		offsetY: offsetY,
	}
}

// zero centered
func (f *ImageField) Get(x, y float32) float32 {
	// todo : blend colors
	c := f.pixels.Get(int(x+float32(f.offsetX)), int(y+float32(f.offsetY)))
	return Brightness(c)
}

/** LAYER HELPERS **/

type FieldLayer struct {
	field   Field
	loColor rl.Color
	hiColor rl.Color
	dirty   bool
}

func (fl *FieldLayer) Update(env *Env, g *sg.Graphics) {

}

func (fl *FieldLayer) Draw(env *Env, g *sg.Graphics) {
	g.Clear()
	g.BeginAdditiveBlend()
	//rl.ClearBackground(rl.Blank)
	//rl.BeginBlendMode(rl.BlendAlphaPremultiply)
	for x := range g.WidthInt32() {
		for y := range g.HeightInt32() {
			v := fl.field.Get(float32(x), float32(y))
			clr := LerpCurve(v, 1.3, fl.loColor, fl.hiColor)
			rl.DrawPixel(x, y, clr)
		}
	}
	rl.EndBlendMode()
	fl.dirty = false
}

func (fl *FieldLayer) IsDirty() bool {
	return fl.dirty
}

type AdderField struct {
	fields []Field
}

func (f *AdderField) Get(x, y float32) float32 {
	var z float32 = 0.0
	for _, field := range f.fields {
		z += rl.Clamp(field.Get(x, y), 0.0, 1.0) / float32(len(f.fields))
	}
	return z
}

type SinXYField struct{}

func (f *SinXYField) Get(x, y float32) float32 {
	return float32(0.5 + 0.5*math.Sin(float64(x))*math.Sin(float64(y)))
	//return float32(math.Sin(float64(x * y)))
}
