package splashmenu

import (
	"cosmos/diego/groovy"
	splashmenu "cosmos/diego/groovy/examples/splashmenu/fonts"
	"fmt"
	"image"
	"image/color"
	"math"

	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/inpututil"
	"github.com/hajimehoshi/ebiten/v2/text"
)

var (
// theRand = &randy{12345678, 4185243, 776511, 45411}
)

const (
	scaleRatio  = 12.0
	maxMagWidth = 100
)

//type randy struct {
//	x, y, z, w uint32
//}

type Noisy struct {
	increment    int
	Dimensions   groovy.Area
	magnifier    groovy.Area
	sX           int
	sY           int
	events       map[groovy.SceneEvent]func()
	pixImage     *image.RGBA
	pixSubImage  *image.RGBA
	subTarget    *ebiten.Image
	renderTarget *ebiten.Image
	fader        *ebiten.Image
	//alpha        float32
}

func NewNoisy() Noisy {
	return Noisy{
		increment: 0,
		events:    make(map[groovy.SceneEvent]func()),
		magnifier: groovy.Area{Width: maxMagWidth, Height: maxMagWidth},
	}
}

func (n *Noisy) Update() error {
	n.increment++

	//n.alpha = float32(n.increment) / (60.0 * 5.0) //60fps * 5 seconds = 300frames
	//fmt.Printf("%f, ", n.alpha)

	n.UpdateNoise()
	return nil
}

func (n *Noisy) Draw(screen *ebiten.Image) {
	n.subTarget.WritePixels(n.pixSubImage.Pix)

	screen.WritePixels(n.pixImage.Pix)
	//screen.WritePixels(n.pixSubImage.Pix)

	op := &ebiten.DrawImageOptions{}
	op.GeoM.Scale(1/scaleRatio, 1/scaleRatio)
	n.renderTarget.DrawImage(n.subTarget, op)
	op = &ebiten.DrawImageOptions{}
	op.GeoM.Scale(scaleRatio, scaleRatio)
	op.GeoM.Translate(float64(n.sX)-maxMagWidth/2, float64(n.sY)-maxMagWidth/2)

	screen.DrawImage(n.renderTarget, op)

	//screen.DrawImage(n.subTarget, nil)

	text.Draw(screen, fmt.Sprintf("%04d, ", n.sX), splashmenu.SplashFont.Menu, n.Dimensions.Width/2-58, n.Dimensions.Height/2+18, color.White)
	text.Draw(screen, fmt.Sprintf("%04d ", n.sY), splashmenu.SplashFont.Menu, n.Dimensions.Width/2, n.Dimensions.Height/2+18, color.White)

	//op = &ebiten.DrawImageOptions{}
	//op.ColorScale.Scale(1, 1, 1, n.alpha)
	//screen.DrawImage(n.fader, op)

	text.Draw(screen, "Q TO EXIT", splashmenu.SplashFont.Title, n.Dimensions.Width/2-77, n.Dimensions.Height/2, color.RGBA{0xff, 0xff, 0xff, uint8(n.increment / (60 * 2) % 0xff)})
}

// register scenevent handler
func (n *Noisy) SetEventHandler(event groovy.SceneEvent, f func()) {
	n.events[event] = f
}

// set the current scene dimensions
func (n *Noisy) SetDimensions(a groovy.Area) {
	n.Dimensions = a
	n.pixImage = image.NewRGBA(image.Rect(0, 0, a.Width, a.Height))
	n.fader = ebiten.NewImage(a.Width, a.Height)
	n.fader.Fill(color.RGBA{0x00, 0x00, 0x00, 0xff})

	n.pixSubImage = image.NewRGBA(image.Rect(0, 0, n.magnifier.Width, n.magnifier.Height))
	n.subTarget = ebiten.NewImage(n.magnifier.Width, n.magnifier.Height)
	n.renderTarget = ebiten.NewImage(n.magnifier.Width, n.magnifier.Height)
}

func (n *Noisy) UpdateNoise() {
	//update cursor position and lock it into the game region bounds
	n.sX, n.sY = ebiten.CursorPosition()
	n.sX = int(math.Min(float64(n.sX), float64(n.Dimensions.Width-1)))
	n.sX = int(math.Max(float64(n.sX), 0))
	n.sY = int(math.Min(float64(n.sY), float64(n.Dimensions.Height-1)))
	n.sY = int(math.Max(float64(n.sY), 0))

	l := n.Dimensions.Width * n.Dimensions.Height

	for i := 0; i < l; i++ {
		//x := theRand.next()
		//n.pixImage.Pix[4*i] = uint8(x >> 24)
		//n.pixImage.Pix[4*i+1] = uint8(x >> 16)
		//n.pixImage.Pix[4*i+2] = uint8(x >> 8)
		//n.pixImage.Pix[4*i+3] = 0xff

		ballsMode := int(float32(i) * (float32(n.increment) / 60.0))

		n.pixImage.Pix[4*i] = uint8(n.increment)
		n.pixImage.Pix[4*i] = uint8(i % 0xff)
		n.pixImage.Pix[4*i+1] = uint8(i >> 16 % 0xff)
		n.pixImage.Pix[4*i+2] = uint8(i >> 24 % 0xff)
		n.pixImage.Pix[4*i+3] = uint8(ballsMode) % 0xFF
	}

	startIdx := n.sX * n.sY * 4
	endIdx := startIdx + n.magnifier.Width*n.magnifier.Height*4

	if endIdx >= l*4 {
		delta := endIdx - l*4
		startIdx = startIdx - delta
		endIdx = endIdx - delta
	}

	copy(n.pixSubImage.Pix[:], n.pixImage.Pix[startIdx:endIdx])

	//check for user input to transition scene
	if inpututil.IsKeyJustPressed(ebiten.KeyQ) {
		if n.events[groovy.COMPLETED] != nil {
			n.events[groovy.COMPLETED]()
		}
	}
}

//func (r *randy) next() uint32 {
//	// math/rand is too slow to keep 60 FPS on web browsers.
//	// Use Xorshift instead: http://en.wikipedia.org/wiki/Xorshift
//	t := r.x ^ (r.x << 11)
//	r.x, r.y, r.z = r.y, r.z, r.w
//	r.w = (r.w ^ (r.w >> 19)) ^ (t ^ (t >> 8))
//	return r.w
//}
