package game

import (
	"fmt"
	"image/color"
	"log/slog"
	"openquell/assets"
	"openquell/config"
	"openquell/gameui"
	"openquell/observers"

	"github.com/ebitenui/ebitenui"
	"github.com/ebitenui/ebitenui/image"
	"github.com/ebitenui/ebitenui/widget"

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

type SelectScene struct {
	Game          *Game
	Next          SceneName
	Whoami        SceneName
	UseCache      bool
	Ui            *ebitenui.UI
	SelectedLevel int
}

func NewSelectScene(game *Game) Scene {
	scene := &SelectScene{Whoami: Select, Game: game, Next: Select}

	scene.SetupUI()

	return scene
}

func (scene *SelectScene) SetLevel(level int) {}

func (scene *SelectScene) GetNext() SceneName {
	return scene.Next
}

func (scene *SelectScene) ResetNext() {
	scene.Next = scene.Whoami
}

func (scene *SelectScene) SetNext(next SceneName) {
	scene.Next = next
}

func (scene *SelectScene) Clearscreen() bool {
	// both level_scene AND the popup must not clear to get an actual popup
	return true
}

func (scene *SelectScene) Update() error {
	scene.Ui.Update()

	if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
		scene.SetNext(Menu)
	}

	return nil
}

func (scene *SelectScene) Draw(screen *ebiten.Image) {
	scene.Ui.Draw(screen)
}

type LevelEntry struct {
	Id     int
	Number int
	Name   string
}

func (scene *SelectScene) SetupUI() {
	gameobserver := observers.GetGameObserver(scene.Game.World)

	rowContainer := gameui.NewRowContainer()

	label := widget.NewText(
		widget.TextOpts.Text("Select Level", *assets.FontRenderer.FontBig, config.FontColorFG),
		widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter),
	)

	levels := make([]any, 0, len(scene.Game.Levels))
	for id := 0; id < len(scene.Game.Levels); id++ {
		levels = append(levels, LevelEntry{Id: id, Number: scene.Game.Levels[id].Number, Name: scene.Game.Levels[id].Name})
	}

	slog.Debug("levels", "levels", levels)
	buttonImage, err := gameui.LoadButtonImage()
	if err != nil {
		panic(err)
	}

	list := widget.NewList(
		// Set how wide the list should be
		widget.ListOpts.ContainerOpts(widget.ContainerOpts.WidgetOpts(
			widget.WidgetOpts.MinSize(150, 0),
			widget.WidgetOpts.LayoutData(widget.RowLayoutData{
				Position:  widget.RowLayoutPositionCenter,
				Stretch:   true,
				MaxHeight: 200,
			}),
		)),
		// Set the entries in the list
		widget.ListOpts.Entries(levels),
		widget.ListOpts.ScrollContainerOpts(
			// Set the background images/color for the list
			widget.ScrollContainerOpts.Image(&widget.ScrollContainerImage{
				Idle:     image.NewNineSliceColor(color.NRGBA{100, 100, 100, 255}),
				Disabled: image.NewNineSliceColor(color.NRGBA{100, 100, 100, 255}),
				Mask:     image.NewNineSliceColor(color.NRGBA{100, 100, 100, 255}),
			}),
		),
		widget.ListOpts.SliderOpts(
			// Set the background images/color for the background of the slider track
			widget.SliderOpts.Images(&widget.SliderTrackImage{
				Idle:  image.NewNineSliceColor(color.NRGBA{100, 100, 100, 255}),
				Hover: image.NewNineSliceColor(color.NRGBA{100, 100, 100, 255}),
			}, buttonImage),
			widget.SliderOpts.MinHandleSize(5),
			// Set how wide the track should be
			widget.SliderOpts.TrackPadding(widget.NewInsetsSimple(2))),
		// Hide the horizontal slider
		widget.ListOpts.HideHorizontalSlider(),
		// Set the font for the list options
		widget.ListOpts.EntryFontFace(*assets.FontRenderer.FontNormal),
		// Set the colors for the list
		widget.ListOpts.EntryColor(&widget.ListEntryColor{
			Selected:                   color.NRGBA{0, 255, 0, 255},
			Unselected:                 color.NRGBA{254, 255, 255, 255},
			SelectedBackground:         color.NRGBA{R: 130, G: 130, B: 200, A: 255},
			SelectedFocusedBackground:  color.NRGBA{R: 130, G: 130, B: 170, A: 255},
			FocusedBackground:          color.NRGBA{R: 170, G: 170, B: 180, A: 255},
			DisabledUnselected:         color.NRGBA{100, 100, 100, 255},
			DisabledSelected:           color.NRGBA{100, 100, 100, 255},
			DisabledSelectedBackground: color.NRGBA{100, 100, 100, 255},
		}),
		// This required function returns the string displayed in the list
		widget.ListOpts.EntryLabelFunc(func(e interface{}) string {
			return fmt.Sprintf("%02d %s", e.(LevelEntry).Number, e.(LevelEntry).Name)
		}),
		// Padding for each entry
		widget.ListOpts.EntryTextPadding(widget.NewInsetsSimple(5)),
		// Text position for each entry
		widget.ListOpts.EntryTextPosition(widget.TextPositionStart, widget.TextPositionCenter),
		// This handler defines what function to run when a list item is selected.
		widget.ListOpts.EntrySelectedHandler(func(args *widget.ListEntrySelectedEventArgs) {
			entry := args.Entry.(LevelEntry)
			fmt.Println("Entry Selected: ", entry)
			gameobserver.CurrentLevel = entry.Id
		}),
	)

	buttonContainer := widget.NewContainer(
		widget.ContainerOpts.Layout(widget.NewGridLayout(
			widget.GridLayoutOpts.Columns(2),
			widget.GridLayoutOpts.Padding(widget.NewInsetsSimple(30)),
			widget.GridLayoutOpts.Spacing(20, 10),
			widget.GridLayoutOpts.Stretch([]bool{true, false}, []bool{false, true}),
		)),
	)

	buttonPlay := gameui.NewMenuButton("Play selected level", *assets.FontRenderer.FontNormal,
		func(args *widget.ButtonClickedEventArgs) {
			scene.SetNext(Play)
		})

	buttonAbort := gameui.NewMenuButton("Back", *assets.FontRenderer.FontNormal,
		func(args *widget.ButtonClickedEventArgs) {
			scene.SetNext(Menu)
		})

	buttonContainer.AddChild(buttonPlay)
	buttonContainer.AddChild(buttonAbort)

	rowContainer.AddChild(label)
	rowContainer.AddChild(list)
	rowContainer.AddChild(buttonContainer)

	scene.Ui = &ebitenui.UI{
		Container: rowContainer.Container(),
	}
}
