package ocelot.desktop.node

import ocelot.desktop.ColorScheme
import ocelot.desktop.entity.traits.OcelotInterface
import ocelot.desktop.geometry.FloatUtils.ExtendedFloat
import ocelot.desktop.geometry.Vector2D
import ocelot.desktop.graphics.Graphics
import ocelot.desktop.node.OcelotLogParticleNode._
import ocelot.desktop.ui.UiHandler
import ocelot.desktop.ui.event.BrainEvent

import scala.collection.mutable
import scala.util.Random

trait OcelotLogParticleNode extends Node {
  private case class LogParticle(
    var time: Float = -LogParticleGrow,
    angle: Float = Random.between(0f, 2 * math.Pi.toFloat * LogParticleMaxAngle),
  )

  // access should be synchronized because log particles are added in the update thread
  private val logParticles = mutable.ArrayDeque.empty[LogParticle]

  private def addLogParticle(): Unit = logParticles.synchronized {
    if (logParticles.length < MaxLogParticles) {
      logParticles += LogParticle()
    }
  }

  eventHandlers += {
    case BrainEvent(OcelotInterface.LogEvent.CardToUser(_, _)) =>
      addLogParticle()
  }

  override def update(): Unit = {
    super.update()

    logParticles.synchronized {
      logParticles.foreach(particle => particle.time += LogParticleMoveSpeed * UiHandler.dt)
      logParticles.filterInPlace(_.time <= 1f)
    }
  }

  private def drawLogParticles(g: Graphics): Unit = logParticles.synchronized {
    for (particle <- logParticles) {
      val size = (1 + particle.time / LogParticleGrow).clamp() * LogParticleSize
      val offset = particle.time.clamp() * LogParticleMoveDistance
      val alpha = 1 - particle.time.clamp()

      val r1 = (bounds.w max bounds.h) / math.sqrt(2) + offset + LogParticlePadding
      val r2 = r1 + size

      for (i <- 0 until LogParticleCount) {
        val angle = particle.angle + (2 * math.Pi).toFloat * i / LogParticleCount
        val v = Vector2D.unit(angle)
        val p1 = v * r1 + bounds.center
        val p2 = v * r2 + bounds.center
        g.line(p1, p2, 1f, ColorScheme("LogParticle").mapA(_ => alpha))
      }
    }
  }

  override def drawParticles(g: Graphics): Unit = {
    super.drawParticles(g)
    drawLogParticles(g)
  }
}

object OcelotLogParticleNode {
  private val MaxLogParticles: Int = 15
  private val LogParticleMaxAngle: Float = 0.25f
  private val LogParticleCount: Int = 12
  private val LogParticleGrow: Float = 0.25f
  private val LogParticlePadding: Float = 2f
  private val LogParticleSize: Float = 10f
  private val LogParticleMoveSpeed: Float = 1f
  private val LogParticleMoveDistance: Float = 20f
}
