package ocelot.desktop.node

import ocelot.desktop.color.RGBAColorNorm
import ocelot.desktop.geometry.{Size2D, Vector2D}
import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.node.SmokeParticleNode._
import ocelot.desktop.ui.UiHandler
import ocelot.desktop.ui.particle.Particle
import ocelot.desktop.util.Spritesheet

import scala.util.Random

trait SmokeParticleNode extends Node {
  protected def emitSmoke(): Unit = synchronized {
    for (_ <- 1 to randomCount) {
      UiHandler.root.workspaceView.particleSystem.add(new SmokeParticle)
    }
  }

  private class SmokeParticle extends Particle(ttl = randomDuration) {
    private val color: RGBAColorNorm = randomColor
    private var velocity: Vector2D = Vector2D(randomVelocityComponent, randomVelocityComponent)
    private var offset: Vector2D = Vector2D(0, 0)

    override def update(dt: Float): Unit = {
      time += dt
      offset += (velocity + SmokeParticleVolatilizationSpeed) * dt * speed
      velocity *= math.pow(SmokeParticleVelocityDamping, dt).toFloat
    }

    override def draw(g: Graphics): Unit = {
      val spriteRect = Spritesheet.sprites(IconSource.Particles.Smoke.path)

      val animationFrameCount = spriteRect.h / spriteRect.w
      val animationFrame = (time / ttl * animationFrameCount).toInt

      val particlePosition = bounds.center + offset - SmokeParticleSize.toVector * .5f

      g.sprite(
        IconSource.Particles.Smoke.path,
        particlePosition.x,
        particlePosition.y,
        SmokeParticleSize.width,
        SmokeParticleSize.height,
        color,
        Some(spriteRect.copy(
          y = spriteRect.y + animationFrame * spriteRect.w,
          h = spriteRect.w,
        )),
      )
    }
  }
}

private object SmokeParticleNode {
  private final val SmokeParticleSize: Size2D = Size2D(32, 32)
  private final val SmokeParticleVelocityRange: Float = 300
  private final val SmokeParticleVolatilizationSpeed: Vector2D = Vector2D(0, -50)
  private final val SmokeParticleVelocityDamping: Float = .1f
  private final val SmokeParticleCount: (Int, Int) = (10, 20)
  private final val SmokeParticleAnimationDuration: (Float, Float) = (1f, 4f)

  private def randomVelocityComponent: Float = Random.between(
    -SmokeParticleVelocityRange,
    SmokeParticleVelocityRange,
  )
  private def randomColor: RGBAColorNorm = {
    val channel = Random.between(.5f, .9f)
    RGBAColorNorm(channel, channel, channel)
  }
  private def randomDuration: Float = Random.between(
    SmokeParticleAnimationDuration._1,
    SmokeParticleAnimationDuration._2,
  )
  private def randomCount: Int = Random.between(
    SmokeParticleCount._1,
    SmokeParticleCount._2,
  )
}
