package wow.doge.mygame.game.entities

import akka.actor.typed.ActorRef
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.scaladsl.Behaviors
import io.estatico.newtype.macros.newtype
import wow.doge.mygame.game.entities.CharacterStats.HealHealth

case class CharacterStats(hp: CharacterStats.Health, stamina: Int)
object CharacterStats {
  @newtype case class HealHealth(toInt: Int)
  @newtype case class DamageHealth(toInt: Int)
  @newtype case class Health(toInt: Int)
  object Health {
    implicit class HealthOps(private val h: Health) extends AnyVal {
      // def +(v: Int): Health = Health(h.toInt + v)
      // def -(v: Int): Health = Health(h.toInt - v)
      // def *(v: Int): Health = Health(h.toInt * v)
      // def /(v: Int): Health = Health(h.toInt / v)
      def :+(v: HealHealth): Health = Health(h.toInt + v.toInt)
      def -(v: DamageHealth): Health = Health(h.toInt - v.toInt)
    }
  }
  @newtype case class HealStamina(toInt: Int)
  @newtype case class DamageStamina(toInt: Int)
  @newtype case class Stamina(toInt: Int)
  object Stamina {
    implicit class StaminaOps(private val h: Stamina) extends AnyVal {
      // def +(v: Int): Stamina = Stamina(h.toInt + v)
      // def -(v: Int): Stamina = Stamina(h.toInt - v)
      // def *(v: Int): Stamina = Stamina(h.toInt * v)
      // def /(v: Int): Stamina = Stamina(h.toInt / v)
      def :+(v: HealStamina): Stamina = Stamina(h.toInt + v.toInt)
      def -(v: DamageStamina): Stamina = Stamina(h.toInt - v.toInt)
    }
  }
  // object Stamina {
  //   implicit class StaminaOps(private val h: Stamina) extends AnyVal {
  //     def +(v: Health): Stamina = Stamina(h.toInt + v.toInt)
  //     def -(v: Health): Stamina = Stamina(h.toInt - v.toInt)
  //     def *(v: Health): Stamina = Stamina(h.toInt * v.toInt)
  //     def /(v: Health): Stamina = Stamina(h.toInt / v.toInt)
  //   }
  // }

  // object Damage {
  //   implicit class DamageOps(private val h: Damage) extends AnyVal {
  //     def +(v: Health): Damage = Damage(h.toInt + v.toInt)
  //     def -(v: Health): Damage = Damage(h.toInt - v.toInt)
  //     def *(v: Health): Damage = Damage(h.toInt * v.toInt)
  //     def /(v: Health): Damage = Damage(h.toInt / v.toInt)
  //   }
  // }

}

object StatsActor {

  sealed trait Command
//   case class TakeDamage(value: Int) extends Command
  case class TakeDamageResult(
      value: CharacterStats.DamageHealth,
      replyTo: ActorRef[(Boolean, CharacterStats)]
  ) extends Command
  case class HealResult(value: HealHealth) extends Command
  case class CurrentStats(replyTo: ActorRef[CharacterStats]) extends Command

  class Props(
      startingHealth: CharacterStats.Health,
      startingStamina: CharacterStats.Stamina
  ) {
    def behavior =
      Behaviors.setup[Command] { ctx =>
        new StatsActor(ctx, this)
          .receive(
            State(CharacterStats(startingHealth, startingStamina.toInt))
          )
      }
  }

  case class State(stats: CharacterStats)
}
class StatsActor(
    ctx: ActorContext[StatsActor.Command],
    props: StatsActor.Props
) {
  import StatsActor._
  import CharacterStats._
  import com.softwaremill.quicklens._
  def receive(state: State): Behavior[Command] =
    Behaviors.receiveMessage[Command] {
      // Todo add min max values
      //   case TakeDamage(value) =>
      //     val nextState =
      //       if (state.stats.hp - value <= 0)
      //         state.modify(_.stats.hp).setTo(0)
      //       else
      //         state.modify(_.stats.hp).using(_ - value)
      //     receive(nextState)
      case TakeDamageResult(value, replyTo) =>
        val nextState = if ((state.stats.hp - value).toInt <= 0) {
          replyTo ! true -> state.stats
          state.modify(_.stats.hp).setTo(Health(0))
        } else {
          replyTo ! false -> state.stats
          state.modify(_.stats.hp).using(_ - value)
        }
        receive(nextState)
      case HealResult(value) =>
        receive(state.modify(_.stats.hp).using(_ :+ value))
      case CurrentStats(replyTo) =>
        replyTo ! state.stats
        Behaviors.same
    }
}
