package ui

import (
	"image"

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

func init() {
	registerBuilder(menus.TypeSimpleButton, registerSimpleButton)
	registerBuilder(menus.TypeInvokeButton, registerInvokeButton)
	registerBuilder(menus.TypeMainButton, registerMainButton)
	registerBuilder(menus.TypeDoorHotspot, registerDoorHotspot)
	registerBuilder(menus.TypeDoorHotspot2, registerDoorHotspot)
	registerBuilder(menus.TypeDoorHotspot3, registerDoorHotspot)
}

// A button without hover animation
// FIXME: Keyboard.mnu has TypeSimpleButton instances that seem to include a
// hover in the SpriteId field
type button struct {
	path string

	baseSpr   *assetstore.Sprite
	clickSpr  *assetstore.Sprite
	frozenSpr *assetstore.Sprite

	clickImpl
	freezeImpl
	hoverImpl
}

// A button with hover animation
type mainButton struct {
	hoverAnim animation

	button
}

func registerSimpleButton(d *Driver, r *menus.Record) error {
	// FIXME: LevelPly.mnu specifies a menu oddly. This tweak gets us past it
	if d.Name == "levelply" && r.Id == 2 {
		return nil
	}

	return registerButton(d, r, r.SpriteId[0])
}

func registerInvokeButton(d *Driver, r *menus.Record) error {
	return registerButton(d, r, r.Share)
}

func registerMainButton(d *Driver, r *menus.Record) error {
	sprites, err := d.menu.Sprites(r.Share, 3) // base, pressed, disabled
	if err != nil {
		return err
	}

	hovers, err := d.menu.Images(r.SpriteId[0], r.DrawType)
	if err != nil {
		return err
	}

	btn := &mainButton{
		hoverAnim: animation(hovers),
		button: button{
			path:      r.Path(),
			baseSpr:   sprites[0],
			clickSpr:  sprites[1],
			frozenSpr: sprites[2],
			hoverImpl: hoverImpl{text: r.Text},
		},
	}

	d.clickables = append(d.clickables, btn)
	d.freezables = append(d.freezables, btn)
	d.hoverables = append(d.hoverables, btn)
	d.paintables = append(d.paintables, btn)

	return nil
}

func registerDoorHotspot(d *Driver, r *menus.Record) error {
	sprites, err := d.menu.Sprites(r.Share, 2) // base, pressed
	if err != nil {
		return err
	}

	btn := &button{
		path:      r.Path(),
		baseSpr:   sprites[0],
		clickSpr:  sprites[1],
		frozenSpr: sprites[0], // No disabled sprite
		hoverImpl: hoverImpl{text: r.Text},
	}

	d.clickables = append(d.clickables, btn)
	d.freezables = append(d.freezables, btn)
	d.hoverables = append(d.hoverables, btn)
	d.paintables = append(d.paintables, btn)

	return nil

}

func registerButton(d *Driver, r *menus.Record, spriteId int) error {
	sprites, err := d.menu.Sprites(spriteId, 3) // base, pressed, disabled
	if err != nil {
		return err
	}

	btn := &button{
		path:      r.Path(),
		baseSpr:   sprites[0],
		clickSpr:  sprites[1],
		frozenSpr: sprites[2],
		hoverImpl: hoverImpl{text: r.Text},
	}

	d.clickables = append(d.clickables, btn)
	d.freezables = append(d.freezables, btn)
	d.hoverables = append(d.hoverables, btn)
	d.paintables = append(d.paintables, btn)

	return nil
}

func (b *button) id() string {
	return b.path
}

func (b *button) bounds() image.Rectangle {
	return b.baseSpr.Rect
}

func (b *button) mouseDownState() bool {
	if b.isFrozen() {
		return false
	}

	return b.clickImpl.mouseDownState()
}

func (b *button) registerMouseClick() {
	if !b.isFrozen() {
		b.clickImpl.registerMouseClick()
	}
}

func (b *button) regions(tick int) []region {
	if b.isFrozen() {
		return oneRegion(b.bounds().Min, b.frozenSpr.Image)
	}

	if b.mouseDownState() {
		return oneRegion(b.bounds().Min, b.clickSpr.Image)
	}

	return oneRegion(b.bounds().Min, b.baseSpr.Image)
}

func (m *mainButton) regions(tick int) []region {
	if !m.isFrozen() && !m.mouseDownState() && m.hoverState() {
		return oneRegion(m.bounds().Min, m.hoverAnim.image(tick))
	}

	return m.button.regions(tick)
}
