package wow.doge.mygame.implicits

import com.simsilica.es.ComponentFilter
import com.simsilica.es.EntityComponent
import com.simsilica.es.EntityData
import com.simsilica.es.EntitySet
import com.simsilica.es.Filters
import scala.reflect.ClassTag
import scala.util.Try

class EntityQuery(ed: EntityData) {
  private var cfilter: Option[ComponentFilter[_ <: EntityComponent]] = None
  private val buf = collection.mutable.ListBuffer.empty[Class[_]]

  def filter[T <: EntityComponent](field: String, value: Object)(implicit
      ev: ClassTag[T]
  ): EntityQuery = {
    val c = ev.runtimeClass.asInstanceOf[Class[T]]
    cfilter = Try(Filters.fieldEquals(c, field, value)).toOption
    this
  }

  def filterOr[T <: EntityComponent](operands: ComponentFilter[_ <: T]*)(
      implicit ev: ClassTag[T]
  ): EntityQuery = {
    val c = ev.runtimeClass.asInstanceOf[Class[T]]
    cfilter = Try(Filters.or(c, operands: _*)).toOption
    this
  }

  def filterAnd[T <: EntityComponent](operands: ComponentFilter[_ <: T]*)(
      implicit ev: ClassTag[T]
  ): EntityQuery = {
    val c = ev.runtimeClass.asInstanceOf[Class[T]]
    cfilter = Try(Filters.and(c, operands: _*)).toOption
    this
  }

  def component[T <: EntityComponent]()(implicit
      ev: ClassTag[T]
  ): EntityQuery = {
    val c = ev.runtimeClass
    buf += c
    this
  }

  def components[T <: EntityComponent](lst: Class[T]*): EntitySet = {
    ed.getEntities(lst: _*)
  }

  def result: EntitySet =
    cfilter.fold(ed.getEntities(buf.toList: _*)) { filters =>
      ed.getEntities(filters, buf.toList: _*)
    }
}
