package flow

import (
	"fmt"

	"code.ur.gs/lupine/ordoor/internal/assetstore"
	"code.ur.gs/lupine/ordoor/internal/ui"
)

type driverName string

const (
	// Names of all the drivers
	main      driverName = "Main"
	levelPly  driverName = "LevelPly"
	singles   driverName = "Singles"
	randomMap driverName = "RandomMap"
	newGame   driverName = "NewGame"
	loadGame  driverName = "LoadGame"
	options   driverName = "Options"
	kbd       driverName = "Keyboard"
	bridge    driverName = "Bridge"
	briefing  driverName = "Briefing"
	choices   driverName = "Choices"
	saveGame  driverName = "SaveGame"
	credits   driverName = "Credits"
	arrange   driverName = "Arrange"

	configureUltEquip      driverName = "Configure_UltEquip"
	configureVehiclesUltra driverName = "Configure_Vehicles_Ultra"

	mainGame driverName = "MainGame"
)

var (
	driverNames = []driverName{
		main, levelPly, singles, randomMap, newGame, loadGame, options, kbd,
		bridge, briefing, choices, saveGame, credits, arrange,
		configureUltEquip, configureVehiclesUltra,
		mainGame,
	}

	menuTransforms = map[driverName]func(*assetstore.Menu){
		mainGame: offsetMainGame,
	}
)

// FIXME: HURK: MainGame elements need changes to show up in the right place
func offsetMainGame(menu *assetstore.Menu) {
	for _, group := range menu.Groups() {
		id := group.ID

		// Bottom-aligned, not top-aligned
		if id == 1 || id == 2 || id == 3 || id == 4 || id == 5 || id == 6 ||
			id == 7 || id == 8 || id == 9 || id == 10 || id == 15 || id == 16 {
			group.Y = 320 // Down by 320px

			// FIXME: in reality, this appears to be a property of the group only
			for _, rec := range group.Records {
				rec.Y = 320
			}
		}

		// Right-aligned, not left-aligned
		// FIXME: this presents problems as there are two sizes and both need to
		// be right-aligned, so a static offset won't quite work
		// if id == 14 {
		// 	group.X = 400 (or so)
		// }

		// Left-aligned, not centered
		// FIXME: we're re-using the X-CORD and Y-CORD elements here. How do we
		// signal a negative number?
		// if id == 18 {
		// 	group.X = 0
		// }
	}
}

func buildDriver(assets *assetstore.AssetStore, name driverName) (*ui.Driver, error) {
	menu, err := assets.Menu(string(name))
	if err != nil {
		return nil, err
	}

	if tf, ok := menuTransforms[name]; ok {
		tf(menu)
	}

	driver, err := ui.NewDriver(assets, menu)
	if err != nil {
		return nil, err
	}

	return driver, nil
}

func (f *Flow) returnToLastDriver(from driverName) func() {
	return func() {
		to, ok := f.returns[from]
		if !ok {
			f.exit = fmt.Errorf("Couldn't work out where to return to from %v", from)
			return
		}

		delete(f.returns, from)

		f.setDriverNow(to)
	}
}

// from is the child menu, to is the parent
func (f *Flow) returnToLastDriverNow(from driverName) error {
	to, ok := f.returns[from]
	if !ok {
		return fmt.Errorf("Couldn't work out where to return to from %v", from)
	}

	delete(f.returns, from)

	f.setDriverNow(to)
	return nil
}

func (f *Flow) setDriver(name driverName) func() {
	return func() {
		f.setDriverNow(name)
	}
}

func (f *Flow) setDriverNow(name driverName) {
	f.current = f.drivers[name]
}

// from is the parent menu, to is the child
func (f *Flow) setReturningDriver(from, to driverName) func() {
	return func() {
		f.setReturningDriverNow(from, to)
	}
}

func (f *Flow) setReturningDriverNow(from, to driverName) {
	f.returns[to] = from
	f.setDriverNow(to)
}
