package systems

import (
	"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
	"lab.zaar.be/thefish/alchemyst-go/engine/fov"
	"lab.zaar.be/thefish/alchemyst-go/engine/fov/precomputed_shade"
	"lab.zaar.be/thefish/alchemyst-go/engine/gamestate"
	"lab.zaar.be/thefish/alchemyst-go/engine/types"
	"lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
	"time"
)

var fovRecompute = true
var redraw = false


type TerrainRenderSystem struct {
	Viewport     *mainwindow.ViewPort
	state        *gamestate.GameState
	layer        *mainwindow.Layer
	animateTiles *time.Ticker
	fov 		 fov.Fov
	TorchRadius  int
	redraw       bool
	fovRecompute bool
}

func NewTerrainRenderSystem(
	state *gamestate.GameState,
	vp *mainwindow.ViewPort,
	layer *mainwindow.Layer,
)  TerrainRenderSystem {

	trs := TerrainRenderSystem{
		Viewport:vp,
		layer: layer,
		state: state,
		redraw: true,
		fovRecompute: true,
	}

	computedFov := precomputed_shade.NewPrecomputedShade(15)
	computedFov.Init()
	trs.TorchRadius = 12 //fixme move to sight component

	trs.animateTiles = time.NewTicker(time.Second / 12)

	trs.fov = computedFov

	return trs
}

//fixme add to screens/game Exit()
func (trs TerrainRenderSystem) Close() {
	trs.animateTiles.Stop()
	trs.animateTiles = nil //zero pointer to ticker
}

func (trs TerrainRenderSystem) Listen() {
	for {
		select {
		case <-trs.state.FovRecompute:
			fovRecompute = true
		case <-trs.state.Redraw:
			redraw = true
		case <-trs.animateTiles.C:
			redraw = true
		}
	}
}

func (trs TerrainRenderSystem) Process() {
	playerCoords := trs.state.Controller.GetComponent(trs.state.Player, ecs.CoordsComponent).(types.Coords)

	trs.Viewport.Move(trs.state, playerCoords)

	if fovRecompute {
		trs.layer.ClearRect(trs.Viewport.Rect)
		fovRecompute = false
		redraw = true
		trs.fov.ComputeFov(trs.state.Level, playerCoords, trs.TorchRadius)
	}

	if redraw {
		//terrain
		for y := 0; y < trs.Viewport.H; y++ {
			for x := 0; x < trs.Viewport.W; x++ {
				mapCoords := types.Coords{trs.Viewport.CameraCoords.X + x, trs.Viewport.CameraCoords.Y + y}

				if trs.state.Level.InBounds(mapCoords) {
					tile := trs.state.Level.GetTile(mapCoords)
					if tile.Explored || tile.Visible {
						trs.layer.PutToBase(
							x+trs.Viewport.X,
							y+trs.Viewport.Y,
							tile.GetChar(),
							tile.GetRawColor(),
							tile.GetRawBgColor(),
						)
					}
				}
			}
		}
		redraw = false
	}
}

func (trs TerrainRenderSystem) SystemType() string {
	return ecs.TerrainRenderSystem
}