package screens

import (
	"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
	"lab.zaar.be/thefish/alchemyst-go/engine/ecs/systems"
	"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/gamelog"
	"lab.zaar.be/thefish/alchemyst-go/engine/gamestate"
	"lab.zaar.be/thefish/alchemyst-go/engine/items"
	"lab.zaar.be/thefish/alchemyst-go/engine/mob/movement"
	"lab.zaar.be/thefish/alchemyst-go/engine/types"
	"lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
	"lab.zaar.be/thefish/alchemyst-go/util/appctx"
)

type GameScreen struct {
	mw         *mainwindow.MainWindow
	state      *gamestate.GameState
	vp         *mainwindow.ViewPort
	controller *ecs.Controller
	scm        *types.ScreenManager
	fov        fov.Fov
}

func NewGameScreen(mw *mainwindow.MainWindow, state *gamestate.GameState, viewPort *mainwindow.ViewPort, controller *ecs.Controller, scm *types.ScreenManager) *GameScreen {
	ts := &GameScreen{
		mw:         mw,
		state:      state,
		vp:         viewPort,
		controller: controller,
		scm:        scm,
	}

	//fixme move this to fov system
	computedFov := precomputed_shade.NewPrecomputedShade(15)
	computedFov.Init()
	ts.fov = computedFov

	renderLevel := systems.NewLevelRenderSystem(state, ts.controller, viewPort, ts.mw.GetLayer("base"), ts.fov)
	go renderLevel.Listen()

	ts.controller.AddSystem(renderLevel, 50)
	return ts
}

func (ts *GameScreen) UseEcs() bool { return true }
func (ts *GameScreen) Enter() {
	ts.mw.GetLayer("overlay").ClearArea(0, ts.mw.H-3, 30, 3)
	ts.mw.GetLayer("overlay").WithColor("#77777777").
		Print(ts.mw.W-17, 1, "Press [color=white]?[/color] for help")
}
func (ts *GameScreen) Exit() {
	//trs := ts.controller.GetSystem(ecs.LevelRenderSystem)
	//trs.(systems.LevelRenderSystem).Close()
	ts.mw.GetLayer("overlay").ClearArea(0, ts.mw.H-3, 30, 3)
	//remove what we dont need
}

// fixme kry names to action constants!
func (ts *GameScreen) HandleInput(input string) {
	//ts.state.Do(func(){
	switch input {
	case "Up", "k", "KP_8":
		movement.Walk(ts.state.Player, ts.state, 0, -1)
		break
	case "Down", "j", "KP_2":
		movement.Walk(ts.state.Player, ts.state, 0, 1)
		break
	case "Left", "h", "KP_4":
		movement.Walk(ts.state.Player, ts.state, -1, 0)
		break
	case "Right", "l", "KP_6":
		movement.Walk(ts.state.Player, ts.state, 1, 0)
		break
	case "y", "KP_7":
		movement.Walk(ts.state.Player, ts.state, -1, -1)
		break
	case "u", "KP_9":
		movement.Walk(ts.state.Player, ts.state, 1, -1)
		break
	case "b", "KP_1":
		movement.Walk(ts.state.Player, ts.state, -1, 1)
		break
	case "n", "KP_3":
		movement.Walk(ts.state.Player, ts.state, 1, 1)
		break
	case "Shift+/":
		ts.scm.SetScreenByName("help")
		break
	case "Shift+z":
		ts.scm.SetScreenByName("devmenu")
		break

	case "g":
		//get list of carriables on tile
		carrieds := items.FindCarriedUnder(ts.state.Player)
		if len(carrieds) == 0 {
			break
		} //do nothing
		//select if there is more than 1
		if len(carrieds) > 1 {
			appctx.Logger().Warn().Msg("Passing item list to inventory not implemented yet")
		} else {
			//call pickup in selected
			cc := items.Controller.GetComponent(carrieds[0], ecs.CarriedComponent).(items.Carried)
			err := items.Carried.Pickup(cc, ts.state.Player, carrieds[0])
			if err != nil {
				// Message with error
				//gameLog.Msg.Error(err)
				//@fixme!
				appctx.Logger().Warn().Err(err)
				break
			}

		}
		//log picked up
		//gameLog.Msg.Message(err)
		break

	case "i":
		ts.scm.SetScreenByName("inventory")
		break
	default:
		ts.mw.GetLayer("base").ClearArea(0, 3, 40, 1)
		ts.mw.GetLayer("base").Print(1, 3, "Key: "+input)
		ts.mw.GetLayer("base").Print(1, 6, "█")

	}
	if gamelog.Log.RedrawLogs {
		logRect := types.NewRect(1, ts.mw.H-gamelog.Log.MaxHeight-1, ts.mw.W-1, gamelog.Log.MaxHeight)
		ts.mw.GetLayer("overlay").ClearRect(logRect)
		count := 0
		for i := len(gamelog.Log.Messages) - 1; i >= len(gamelog.Log.Messages)-gamelog.Log.MaxHeight; i-- {
			//fmt.Println(gamelog.Log.Messages[i].Message)
			ts.mw.GetLayer("overlay").PutStringInto(logRect, count-2, gamelog.Log.Messages[i].Message, 0)
			count++
		}
		gamelog.Log.RedrawLogs = false
	}
}

func (ts *GameScreen) Render() {
	ts.controller.Process(nil)
}
