package doodle

import (
	"git.kirsle.net/SketchyMaze/doodle/pkg/enum"
	"git.kirsle.net/SketchyMaze/doodle/pkg/level"
	"git.kirsle.net/SketchyMaze/doodle/pkg/log"
	"git.kirsle.net/SketchyMaze/doodle/pkg/uix"
	"git.kirsle.net/SketchyMaze/doodle/pkg/windows"
	"git.kirsle.net/go/render"
	"git.kirsle.net/go/render/event"
	"git.kirsle.net/go/ui"
)

/*
MenuScene holds the main dialog menu UIs for:

* New Level
* Open Level
* Settings

DEPRECATED: migrate these prompts into popup windows to appear
on the MainScene or elsewhere as wanted.
*/
type MenuScene struct {
	// Configuration.
	StartupMenu string
	NewDoodad   bool

	Supervisor *ui.Supervisor

	// Private widgets.
	window *ui.Window

	// Background wallpaper canvas.
	canvas *uix.Canvas

	// Values for the New menu
	newPageType  string
	newWallpaper string

	// Values for the Load/Play menu.
	loadForPlay bool // false = load for edit
}

// Name of the scene.
func (s *MenuScene) Name() string {
	return "Menu"
}

// DebugGetWindow surfaces the underlying private window.
func (s *MenuScene) DebugGetWindow() *ui.Window {
	return s.window
}

// GotoNewMenu loads the MenuScene and shows the "New" window.
func (d *Doodle) GotoNewMenu() {
	log.Info("Loading the MenuScene to the New window")
	scene := &MenuScene{
		StartupMenu: "new",
	}
	d.Goto(scene)
}

// GotoNewDoodadMenu loads the MenuScene and shows the "New" window,
// but selected on the Doodad tab by default.
func (d *Doodle) GotoNewDoodadMenu() {
	log.Info("Loading the MenuScene to the New window")
	scene := &MenuScene{
		StartupMenu: "new",
		NewDoodad:   true,
	}
	d.Goto(scene)
}

// GotoLoadMenu loads the MenuScene and shows the "Load" window.
//
// DEPRECATED: loads the old menu, in dev console run `$ d.GotoLoadMenu()` to see.
func (d *Doodle) GotoLoadMenu() {
	log.Info("Loading the MenuScene to the Load window for Edit Mode")
	scene := &MenuScene{
		StartupMenu: "load",
	}
	d.Goto(scene)
}

// GotoPlayMenu loads the MenuScene and shows the "Load" window for playing a
// level, not editing it.
//
// DEPRECATED: loads the old menu, in dev console run `$ d.GotoPlayMenu()` to see.
func (d *Doodle) GotoPlayMenu() {
	log.Info("Loading the MenuScene to the Load window for Play Mode")
	scene := &MenuScene{
		StartupMenu: "load",
		loadForPlay: true,
	}
	d.Goto(scene)
}

// GotoSettingsMenu loads the settings screen.
func (d *Doodle) GotoSettingsMenu() {
	log.Info("Loading the MenuScene to the Settings Menu")
	scene := &MenuScene{
		StartupMenu: "settings",
	}
	d.Goto(scene)
}

// Setup the scene.
func (s *MenuScene) Setup(d *Doodle) error {
	s.Supervisor = ui.NewSupervisor()

	// Set up the background wallpaper canvas.
	s.canvas = uix.NewCanvas(100, false)
	s.canvas.Resize(render.Rect{
		W: d.width,
		H: d.height,
	})
	s.canvas.LoadLevel(&level.Level{
		Chunker:   level.NewChunker(100),
		Palette:   level.NewPalette(),
		PageType:  level.Bounded,
		Wallpaper: "notebook.png",
	})

	switch s.StartupMenu {
	case "new":
		if err := s.setupNewWindow(d); err != nil {
			return err
		}
	case "load":
		if err := s.setupLoadWindow(d); err != nil {
			return err
		}
	case "settings":
		if err := s.setupSettingsWindow(d); err != nil {
			return err
		}
	default:
		d.FlashError("No Valid StartupMenu Given to MenuScene")
	}

	// Whatever window we got, give it window manager controls under Supervisor.
	s.window.Supervise(s.Supervisor)
	s.window.Compute(d.Engine)

	// Center the window.
	s.window.MoveTo(render.Point{
		X: (d.width / 2) - (s.window.Size().W / 2),
		Y: 60,
	})

	return nil
}

// configureCanvas updates the settings of the background canvas, so a live
// preview of the wallpaper and wrapping type can be shown.
func (s *MenuScene) configureCanvas(pageType level.PageType, wallpaper string) {
	s.canvas.LoadLevel(&level.Level{
		Chunker:   level.NewChunker(100),
		Palette:   level.NewPalette(),
		PageType:  pageType,
		Wallpaper: wallpaper,
	})
}

// setupNewWindow sets up the UI for the "New" window.
func (s *MenuScene) setupNewWindow(d *Doodle) error {
	window := windows.NewAddEditLevel(windows.AddEditLevel{
		Supervisor: s.Supervisor,
		Engine:     d.Engine,
		NewDoodad:  s.NewDoodad,
		OnChangePageTypeAndWallpaper: func(pageType level.PageType, wallpaper string) {
			log.Info("OnChangePageTypeAndWallpaper called: %+v, %+v", pageType, wallpaper)
			s.canvas.Destroy() // clean up old textures
			s.configureCanvas(pageType, wallpaper)
		},
		OnCreateNewLevel: func(lvl *level.Level) {
			d.Goto(&EditorScene{
				DrawingType: enum.LevelDrawing,
				Level:       lvl,
			})
		},
		OnCreateNewDoodad: func(width, height int) {
			d.NewDoodad(width, height)
		},
		OnCancel: func() {
			d.Goto(&MainScene{})
		},
	})
	s.window = window
	window.SetButtons(0)
	window.Show()
	return nil
}

// setupLoadWindow sets up the UI for the "New" window.
func (s *MenuScene) setupLoadWindow(d *Doodle) error {
	window := windows.NewOpenLevelEditor(windows.OpenLevelEditor{
		Supervisor:  s.Supervisor,
		Engine:      d.Engine,
		LoadForPlay: s.loadForPlay,
		OnPlayLevel: func(filename string) {
			d.PlayLevel(filename)
		},
		OnEditLevel: func(filename string) {
			d.EditFile(filename)
		},
		OnCancel: func() {
			d.Goto(&MainScene{})
		},
	})
	s.window = window
	return nil
}

// setupLoadWindow sets up the UI for the "New" window.
func (s *MenuScene) setupSettingsWindow(d *Doodle) error {
	window := windows.NewSettingsWindow(windows.Settings{
		Supervisor: s.Supervisor,
		Engine:     d.Engine,
	})
	window.SetButtons(0)
	s.window = window
	return nil
}

// Loop the editor scene.
func (s *MenuScene) Loop(d *Doodle, ev *event.State) error {
	s.Supervisor.Loop(ev)

	if ev.WindowResized {
		log.Info("Resized to %dx%d", d.width, d.height)
		s.canvas.Resize(render.Rect{
			W: d.width,
			H: d.height,
		})
	}

	return nil
}

// Draw the pixels on this frame.
func (s *MenuScene) Draw(d *Doodle) error {
	// Draw the background canvas.
	s.canvas.Present(d.Engine, render.Origin)

	// TODO: if I don't call Compute here, buttons in the Edit Window get all
	// bunched up. Investigate why later.
	s.window.Compute(d.Engine)

	// Draw the window managed by Supervisor.
	s.Supervisor.Present(d.Engine)

	return nil
}

// Destroy the scene.
func (s *MenuScene) Destroy() error {
	// Free (wallpaper) textures.
	s.canvas.Destroy()

	return nil
}
