package world

import (
	"image/color"

	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/vector"
)

// Surface types

type SurfaceTag int

const (
	TagGround SurfaceTag = iota
	TagWall
	TagPlatform
	TagHazard
)

type Surface struct {
	X      float64
	Y      float64
	Width  float64
	Height float64
	Tag    SurfaceTag
	Color  color.NRGBA
}

func (s *Surface) Bounds() (x, y, width, height float64) {
	return s.X, s.Y, s.Width, s.Height
}

func (s *Surface) Contains(x, y float64) bool {
	return x >= s.X && x <= s.X+s.Width && y >= s.Y && y <= s.Y+s.Height
}

func (s *Surface) IsSolid() bool {
	switch s.Tag {
	case TagGround, TagWall, TagPlatform:
		return true
	case TagHazard:
		return false
	default:
		return false
	}
}

func (s *Surface) IsWalkable() bool {
	switch s.Tag {
	case TagGround, TagPlatform:
		return true
	case TagWall, TagHazard:
		return false
	default:
		return false
	}
}

func (s *Surface) Draw(screen *ebiten.Image) {
	drawX := float32(int(s.X + 0.5))
	drawY := float32(int(s.Y + 0.5))
	drawWidth := float32(int(s.Width + 0.5))
	drawHeight := float32(int(s.Height + 0.5))

	vector.FillRect(
		screen,
		drawX,
		drawY,
		drawWidth,
		drawHeight,
		s.Color,
		false,
	)
}

// World container

type World struct {
	Surfaces []*Surface
}

func NewWorld() *World {
	return &World{
		Surfaces: make([]*Surface, 0),
	}
}

func (w *World) AddSurface(surface *Surface) {
	w.Surfaces = append(w.Surfaces, surface)
}

func (w *World) GetSurfacesWithTag(tag SurfaceTag) []*Surface {
	var result []*Surface
	for _, s := range w.Surfaces {
		if s.Tag == tag {
			result = append(result, s)
		}
	}
	return result
}

func (w *World) GetSurfacesAt(x, y float64) []*Surface {
	var result []*Surface
	for _, s := range w.Surfaces {
		if s.Contains(x, y) {
			result = append(result, s)
		}
	}
	return result
}

func (w *World) CheckCollision(x, y, width, height float64) *Surface {
	for _, s := range w.Surfaces {
		if !s.IsSolid() {
			continue
		}
		if x+width > s.X && x < s.X+s.Width &&
			y+height > s.Y && y < s.Y+s.Height {
			return s
		}
	}
	return nil
}

func (w *World) Draw(screen *ebiten.Image) {
	for _, s := range w.Surfaces {
		s.Draw(screen)
	}
}
