package wow.doge.mygame.state

import ammonite.runtime.Storage.Folder
import ammonite.main.Defaults
import ammonite.Main
import javax.script.ScriptEngine
import com.jme3.app.Application
import com.jme3.app.state.AppState
import akka.actor.typed.scaladsl.AbstractBehavior
import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.Behavior
import akka.actor.typed.ActorRef
import ammonite.util.Res.Success
import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.SpawnProtocol

class ScriptingEngineState(
    sse: ScalaScriptingEngine,
    kse: KotlinScriptingEngine
) extends MyBaseState {

  // implicit val actorSystem =
  //   ActorSystem.create(MyActorSystem(), "rootActor")
  // implicit val timeout: Timeout = Timeout(3.seconds)
  // val scalaScriptActor: Future[ActorRef[ScalaScriptBehavior.Command]] =
  //   actorSystem.ask(
  //     SpawnProtocol.Spawn(
  //       ScalaScriptBehavior(sse.runner),
  //       name = "ScalaScriptCompilerActor",
  //       Props.empty,
  //       _
  //     )
  //   )

  override protected def cleanup(app: Application): Unit = {
    // actorSystem.terminate()
  }

//   override protected def initialize(app: Application): Unit = {
//     super.initialize(app)

//   }
  override def init() = {
    // Future {
    //   while (true) {
    //     // super.update(tpf)
    //     val (res, k) = sse.runner.runScript(
    //       //   os.Path(getClass().getResource("/hello.sc").getPath),
    //       os.pwd / "src" / "main" / "resources" / "hello.sc",
    //       Seq.empty
    //       // Seq(("start", None))
    //       // Scripts.groupArgs(List(""))
    //     )
    //     val ms = res.map(_.asInstanceOf[GameScript])
    //     ms.map(_.start())

    //     val res2 = kse.engine.eval(
    //       os.read(os.pwd / "src" / "main" / "resources" / "hello.main.kts")
    //     )
    //     // val res2 = engine.eval(getClass().getResource("/hello.main.kts").getPath)
    //     // val invoker = engine.asInstanceOf[Invocable]
    //     // val scr = invoker.getInterface(res2, classOf[GameScript])
    //     val scr = res2.asInstanceOf[GameScript]
    //     scr.start()
    //     Thread.sleep(2000)
    //   }
    // }
    // Future {
    //   sse.runner
    //     .runScript(
    //       os.pwd / "src" / "main" / "resources" / "hello2.sc",
    //       Seq.empty
    //     )
    //     ._1
    //     .map(_.asInstanceOf[MyBaseState])
    //     .map(s => stateManager.attach(s))

    //   ()

    // }

    // val res = scalaScriptActor
    //   .map(
    //     _.ask(ref =>
    //       ScalaScriptBehavior.Compile(
    //         ref,
    //         os.pwd / "src" / "main" / "resources" / "hello2.sc"
    //         // os.Path(getClass().getResource("/hello2.sc").getPath)
    //       )
    //     )(Timeout(10.seconds), actorSystem.scheduler)
    //   )
    //   .flatten

    // res.foreach(_ match {
    //   case AppStateResult(state) => {
    //     stateManager.attach(state)
    //   }
    //   case wow.doge.mygame.state.ScalaScriptBehavior.Error(reason) =>
    //     println("error")
    // })

  }

  override def update(tpf: Float): Unit = {}

  override protected def onEnable(): Unit = {}

  override protected def onDisable(): Unit = {}

}

object MyActorSystem {
  def apply(): Behavior[SpawnProtocol.Command] =
    Behaviors.setup { context =>
      // Start initial tasks
      // context.spawn(...)

      SpawnProtocol()
    }
}
class ScalaScriptingEngine(
    val runner: Main = ammonite
      .Main(
        //   predefCode = """
        //   import coursierapi.MavenRepository

        //   interp.repositories.update(
        //     interp.repositories() ::: List(
        //       MavenRepository.of("file://home/rohan/.m2/repository")
        //     )
        //   )

        //   @

        // """,
        defaultPredef = false,
        storageBackend = new Folder(Defaults.ammoniteHome, isRepl = false)
      )
) {}

class KotlinScriptingEngine(val engine: ScriptEngine) {
//   val manager = new ScriptEngineManager()
//   val engine = manager.getEngineByExtension("main.kts")
}

object ScalaScriptBehavior {
  sealed trait Result
  final case class AppStateResult(state: AppState) extends Result
  final case class Error(reason: String) extends Result

  sealed trait Command
  final case class Compile(sender: ActorRef[Result], path: os.Path)
      extends Command
  // final case class CompileScripts(sender: ActorRef[Result], paths: os.Path*)
  // extends Command
  def apply(
      runner: Main = ammonite
        .Main(
          storageBackend = new Folder(
            // os.pwd / "target"
            Defaults.ammoniteHome,
            isRepl = false
          )
        )
  ) =
    Behaviors.setup(ctx => new ScalaScriptActor(runner, ctx))
  private class ScalaScriptActor(
      val runner: Main,
      context: ActorContext[Command]
  ) extends AbstractBehavior[Command](context) {

    override def onMessage(msg: Command): Behavior[Command] = {
      msg match {
        case Compile(sender, path) =>
          context.log.debug(s"Received $path")
          val res = getScript(path)
          println(res)
          sender ! res
          Behaviors.same
        // case CompileScripts(sender, paths) =>
      }
    }

    def getScript(path: os.Path): Result = {
      runner
        .runScript(
          path,
          Seq.empty
        )
        ._1 match {
        case ammonite.util.Res.Exception(t, msg) => Error(msg)

        case Success(obj) =>
          obj match {
            case s: MyBaseState => AppStateResult(s)
            case _              => Error("Unknown script type")
            // AppStateResult(s.asInstanceOf[AppState])
          }

        case _ => Error("Failed to run script")
      }

    }

  }
}
