package ui

import (
	"code.ur.gs/lupine/ordoor/internal/menus"
	"fmt"
	"log"
)

func (d *Driver) registerGroup(group *menus.Group) error {
	// log.Printf("Adding group %v: %#+v", group.Locator, group)

	var dialogue bool

	switch group.Type {
	case menus.TypeStatic, menus.TypeMainBackground, menus.TypeMenu, menus.TypeDragMenu, menus.TypeRadioMenu:
	case menus.TypeDialogue:
		dialogue = true
	default:
		return fmt.Errorf("Unknown group type: %v", group.Type)
	}

	var groupWidget *Widget
	// Groups have a background sprite (FIXME: always?)
	if group.BaseSpriteID() >= 0 {
		var err error
		_, groupWidget, err = d.buildStatic(group.Props())
		if err != nil {
			return err
		}
	} else {
		groupWidget = &Widget{
			Locator: group.Locator,
			Active:  group.Active,
		}
	}

	if dialogue {
		d.dialogues = append(d.dialogues, groupWidget)
	} else {
		d.widgets = append(d.widgets, groupWidget)
	}

	// TRadioGroup is best handled like this
	records, widget, err := d.maybeBuildInventorySelect(group, group.Records)
	if err != nil {
		return err
	}
	if widget != nil {
		groupWidget.Children = append(groupWidget.Children, widget)
	}

	records, widget, err = d.maybeBuildListBox(group, records)
	if err != nil {
		return err
	}
	if widget != nil {
		groupWidget.Children = append(groupWidget.Children, widget)
	}

	for _, record := range records {
		child, err := d.buildRecord(record)
		if err != nil {
			return err
		}

		if child != nil {
			groupWidget.Children = append(groupWidget.Children, child)
		}
	}

	return nil
}

func (d *Driver) buildRecord(r *menus.Record) (*Widget, error) {
	var widget *Widget
	var err error

	switch r.Type {
	case menus.SubTypeSimpleButton, menus.SubTypeInvokeButton:
		_, widget, err = d.buildButton(r.Props())
	case menus.SubTypeDoorHotspot1, menus.SubTypeDoorHotspot2, menus.SubTypeDoorHotspot3:
		_, widget, err = d.buildDoorHotspot(r.Props())
	case menus.SubTypeOverlay:
		_, widget, err = d.buildOverlay(r.Props())
	case menus.SubTypeHypertext:
		_, widget, err = d.buildHypertext(r.Props())
	case menus.SubTypeCheckbox:
		_, widget, err = d.buildCheckbox(r.Props())
	case menus.SubTypeEditBox:
		log.Printf("Unimplemented: SubTypeEditBox: %v", r.Locator) // TODO
	case menus.SubTypeRadioButton:
		log.Printf("Unimplemented: SubTypeRadioButton: %v", r.Locator) // TODO
	case menus.SubTypeDropdownButton:
		log.Printf("Unimplemented: SubTypeDropdownButton: %v", r.Locator) // TODO
	case menus.SubTypeComboBoxItem:
		log.Printf("Unimplemented: SubTypeComboBoxItem: %v", r.Locator) // TODO
	case menus.SubTypeAnimationSample:
		_, widget, err = d.buildAnimationSample(r.Props())
	case menus.SubTypeAnimationHover:
		_, widget, err = d.buildAnimationHover(r.Props())
	case menus.SubTypeMainButton:
		_, widget, err = d.buildMainButton(r.Props())
	case menus.SubTypeSlider:
		_, widget, err = d.buildSlider(r.Props()) // TODO: take sliders at an earlier point?
	case menus.SubTypeStatusBar:
		log.Printf("Unimplemented: SubTypeStatusBar: %v", r.Locator) // TODO
	default:
		return nil, fmt.Errorf("Unknown record type for %v: %v", r.Locator, r.Type)
	}

	return widget, err
}

func (d *Driver) maybeBuildInventorySelect(group *menus.Group, records []*menus.Record) ([]*menus.Record, *Widget, error) {
	var untouched []*menus.Record
	var touched []*menus.Record

	for _, record := range records {
		if record.Type == menus.SubTypeInventorySelect {
			touched = append(touched, record)
		} else {
			untouched = append(untouched, record)
		}
	}

	if len(touched) == 0 {
		return untouched, nil, nil
	}

	elements := make([]*inventorySelect, len(touched))
	widget := &Widget{
		Locator: group.Locator,
		Active:  group.Active,
	}

	for i, record := range touched {
		element, childWidget, err := d.buildInventorySelect(record.Props())
		if err != nil {
			return nil, nil, err
		}

		elements[i] = element
		widget.Children = append(widget.Children, childWidget)
	}

	elements[0].setValue("1")

	for _, element := range elements {
		element.others = elements
	}

	return untouched, widget, nil
}

func (d *Driver) maybeBuildListBox(group *menus.Group, records []*menus.Record) ([]*menus.Record, *Widget, error) {
	// Unless up, down, thumb, and items, are all present, it's not a listbox
	var up *menus.Record
	var down *menus.Record
	var thumb *menus.Record
	var items []*menus.Record

	var untouched []*menus.Record

	for _, rec := range records {
		switch rec.Type {
		case menus.SubTypeListBoxUp:
			if up != nil {
				return nil, nil, fmt.Errorf("Duplicate up buttons in menu %v", group.Locator)
			}
			up = rec
		case menus.SubTypeListBoxDown:
			if down != nil {
				return nil, nil, fmt.Errorf("Duplicate down buttons in menu %v", group.Locator)
			}
			down = rec
		case menus.SubTypeLineKbd, menus.SubTypeLineBriefing:
			items = append(items, rec)
		case menus.SubTypeThumb:
			if thumb != nil {
				return nil, nil, fmt.Errorf("Duplicate thumbs in menu %v", group.Locator)
			}
			thumb = rec
		default:
			// e.g. maingame:18.12 includes a button that is not part of the box
			untouched = append(untouched, rec)
		}
	}

	// Since not all the elements are present, this isn't a listbox
	if len(items) == 0 || thumb == nil || up == nil || down == nil {
		return untouched, nil, nil
	}

	_, widget, err := d.buildListBox(group, up, down, thumb, items...)
	if err != nil {
		return nil, nil, err
	}

	return untouched, widget, nil
}
