package wow.doge.mygame.game.subsystems.movement

import cats.Id
import com.jme3.bullet.control.BetterCharacterControl
import com.jme3.math.FastMath
import com.jme3.math.Quaternion
import com.jme3.math.Vector3f
import monix.eval.Coeval
import wow.doge.mygame.implicits._
import wow.doge.mygame.math.ImVector3f
import wow.doge.mygame.subsystems.movement.RotateDir
// experiment to see if it would be useful to use an effect wrapper for a typeclass like this
trait CanMove2[-A, F[_]] {
  // def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f
  def move(inst: A, direction: ImVector3f, speedFactor: Float = 20f): F[Unit]
  def location(inst: A): F[ImVector3f]
  def jump(inst: A): F[Unit]
  def stop(inst: A): F[Unit]
  def rotate(inst: A, rotateDir: RotateDir): F[Unit]
}

object Test {
  val x = new BetterCharacterControl(4, 10, 5)
  def test[T](x: T)(implicit cm: CanMove2[T, Id]) = {
    cm.move(x, ImVector3f.ZERO)
  }
}

object CanMove2 {
  implicit val testImpl = new CanMove2[BetterCharacterControl, Id] {

    override def move(
        inst: BetterCharacterControl,
        direction: ImVector3f,
        speedFactor: Float
    ): Id[Unit] = {}

    override def location(inst: BetterCharacterControl): Id[ImVector3f] =
      ImVector3f.ZERO

    override def jump(inst: BetterCharacterControl): Id[Unit] = ???

    override def stop(inst: BetterCharacterControl): Id[Unit] = ???

    override def rotate(
        inst: BetterCharacterControl,
        rotateDir: RotateDir
    ): Id[Unit] = ???

  }
  implicit val implCanMoveForBetterCharacterControl =
    new CanMove2[BetterCharacterControl, Coeval] {
      override def move(
          inst: BetterCharacterControl,
          direction: ImVector3f,
          speedFactor: Float = 20f
      ): Coeval[Unit] =
        Coeval {
          val dir = direction.mutable.normalizeLocal()
          inst.setViewDirection(dir.negate())
          inst.setWalkDirection(dir.mult(speedFactor))
        }
      override def location(inst: BetterCharacterControl) =
        Coeval(inst.getSpatial().getLocalTranslation().immutable)
      override def jump(inst: BetterCharacterControl): Coeval[Unit] =
        Coeval(inst.jump())
      override def rotate(
          inst: BetterCharacterControl,
          rotateDir: RotateDir
      ): Coeval[Unit] =
        Coeval {
          val q =
            rotateDir match {
              case RotateDir.Left =>
                new Quaternion()
                  .fromAngleNormalAxis(5 * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y)
              case RotateDir.Right =>
                new Quaternion()
                  .fromAngleAxis(-5 * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y)
            }

          val tmp = new Vector3f()
          inst.getViewDirection(tmp)
          inst.setViewDirection(q.mult(tmp))
        }
      override def stop(inst: BetterCharacterControl) =
        Coeval(inst.setWalkDirection(Vector3f.ZERO))
    }
}
