package mainwindow

import (
	"errors"
	"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/gamemap"
	"lab.zaar.be/thefish/alchemyst-go/engine/types"
)

var NotInViewError = errors.New("not in ViewPort")

const FPS_LIMIT = 60

type ViewPort struct {
	*types.Rect
	level *gamemap.Level
	layer *Layer
	Fov   fov.Fov
	playerCoords types.Coords
	playerTorchRadius int
}

func NewViewPort(x, y, w, h int, level *gamemap.Level, layer *Layer) *ViewPort {
	//fixme
	fov := precomputed_shade.NewPrecomputedShade(15)
	fov.Init()
	vp := ViewPort{
		Rect:  &types.Rect{x, y, w, h},
		level: level,
		layer: layer,
		Fov:   fov,
	}

	vp.playerCoords = types.Coords{10,10}
	vp.playerTorchRadius = 10

	return &vp
}

func (vp *ViewPort) Move(c *types.Coords) {
	x := c.X - vp.Rect.W/2
	y := c.Y - vp.Rect.H/2

	if x < 0 {
		x = 0
	}
	if y < 0 {
		y = 0
	}
	if x > vp.level.W-vp.W {
		x = vp.level.W - vp.W
	}
	if y > vp.level.H-vp.H {
		x = vp.level.H - vp.H
	}
	//if x != vp.X || y != vp.Y { State.FovRecompute <- struct{}{}}
	vp.X, vp.Y = x, y
}

func (vp *ViewPort) ToVPCoords(c *types.Coords) (newCoords *types.Coords, err error) {
	//coords on map to coords on vp
	x, y := c.X-vp.X, c.Y-vp.Y
	if x < 0 || y < 0 || x >= vp.W || y >= vp.H {
		return &types.Coords{-1, -1}, NotInViewError
	}
	return &types.Coords{x, y}, nil
}

////call only from main thread
//func (vp *ViewPort) Render() {
//	//fixme get these from state chan(s)
//	var fpsTicker int
//	var fovRecompute bool = true
//	redraw := false
//	//fixme get player instance
//
//	vp.Move(&vp.playerCoords)
//	//fixme detect fovRecompute
//	if fovRecompute {
//		vp.layer.Clear(vp.Rect)
//		fovRecompute = false
//		redraw = true
//		//fixme
//
//		vp.Fov.ComputeFov(vp.level, vp.playerCoords, vp.playerTorchRadius)
//	}
//	//increase ticker
//	fpsTicker++
//
//	if redraw || fpsTicker%(FPS_LIMIT/10) == 0 {
//		fpsTicker = 0
//
//		for y := 0; y < vp.H; y++ {
//			for x := 0; x < vp.W; x++ {
//				mapCoords := types.Coords{vp.X + x, vp.Y + y}
//				tile := vp.level.Tiles[mapCoords.X][mapCoords.Y]
//				visible := vp.Fov.IsInFov(mapCoords)
//				if !visible {
//					if tile.MustDraw {
//						//darkened version of landscape
//						vp.layer.WithRawColor(tile.ColorSet.DarkFg()).
//							PutWithRawBackground(mapCoords.X, mapCoords.Y, tile.Char, tile.ColorSet.DarkBg())
//					}
//				} else {
//					if redraw == true || tile.Colordance {
//						vp.layer.WithRawColor(tile.ColorSet.Fg()).
//							PutWithRawBackground(mapCoords.X, mapCoords.Y, tile.Char, tile.ColorSet.Bg())
//						tile.Explored = true
//						tile.MustDraw = true
//					}
//				}
//			}
//		}
//
//	}
//}


func (vp *ViewPort) Render() {
	for y := 0; y < vp.H; y++ {
		for x := 0; x < vp.W; x++ {
			mapCoords := types.Coords{vp.X + x, vp.Y + y}
			tile := vp.level.Tiles[mapCoords.X][mapCoords.Y]
			fg := tile.ColorSet.Fg()
			bg := tile.ColorSet.Bg()
			vp.layer.WithRawColor(fg).
				PutWithRawBackground(mapCoords.X, mapCoords.Y, tile.Char, bg)
		}
	}

}