package item

import (
	"mvvasilev/last_light/engine"
)

type Inventory interface {
	Items() []Item
	Shape() engine.Size
	Push(item Item) bool
	Drop(x, y int) Item
	ItemAt(x, y int) Item
}

type BasicInventory struct {
	contents []Item
	shape    engine.Size
}

func CreateInventory(shape engine.Size) *BasicInventory {
	inv := new(BasicInventory)

	inv.contents = make([]Item, 0, shape.Height()*shape.Width())
	inv.shape = shape

	return inv
}

func (i *BasicInventory) Items() (items []Item) {
	return i.contents
}

func (i *BasicInventory) Shape() engine.Size {
	return i.shape
}

func (inv *BasicInventory) Push(i Item) (success bool) {
	if len(inv.contents) == inv.shape.Area() {
		return false
	}

	itemType := i.Type()

	// Try to first find a matching item with capacity
	for index, existingItem := range inv.contents {
		if existingItem != nil && existingItem.Type().Id() == itemType.Id() {
			if existingItem.Quantity()+1 > existingItem.Type().MaxStack() {
				continue
			}

			it := CreateBasicItem(itemType, existingItem.Quantity()+1)
			inv.contents[index] = &it

			return true
		}
	}

	// Next, try to find an intermediate empty slot to fit this item into
	for index, existingItem := range inv.contents {
		if existingItem == nil {
			inv.contents[index] = i

			return true
		}
	}

	// Finally, just append the new item at the end
	inv.contents = append(inv.contents, i)

	return true
}

func (i *BasicInventory) Drop(x, y int) Item {
	index := y*i.shape.Width() + x

	if index > len(i.contents)-1 {
		return nil
	}

	item := i.contents[index]

	i.contents[index] = nil

	return item
}

func (i *BasicInventory) ItemAt(x, y int) (item Item) {
	index := y*i.shape.Width() + x

	if index > len(i.contents)-1 {
		return nil
	}

	return i.contents[index]
}