package partisan.weforge.xyz.pulse

import android.content.Context
import android.content.res.ColorStateList
import android.graphics.*
import android.util.AttributeSet
import android.view.Choreographer
import android.view.MotionEvent
import android.view.View
import kotlin.math.*
import kotlin.random.Random

class SecretView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : View(context, attrs), Choreographer.FrameCallback {

    private val bulletPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.WHITE
        strokeWidth = 6f
    }
    private val starPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.WHITE
        alpha = 40
        style = Paint.Style.FILL
    }
    private val playerPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.STROKE
        strokeWidth = 4f
    }
    private val enemyPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.STROKE
        strokeWidth = 4f
    }
    private val rocketPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.RED
        style = Paint.Style.STROKE
        strokeWidth = 3f
    }
    private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.WHITE
        textAlign = Paint.Align.CENTER
        textSize = 64f
        typeface = Typeface.DEFAULT_BOLD
    }
    private val retryRect = RectF()
    private val retryPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.DKGRAY
    }
    private val retryTextPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.WHITE
        textAlign = Paint.Align.CENTER
        textSize = 48f
    }
    private var colorSecondary: Int = Color.GREEN

    private var playerX = 0f
    private var viewWidth = 0f
    private var viewHeight = 0f

    private var enemyClearAggression = 0f
    private var adaptiveSpawnTimer = 0L
    private var lastEnemyCount = 0
    private var avgEnemiesPerSecond = 0f

    private var isTouching = false
    private var shieldRechargeTimer = 0L
    private var shieldFlashAlpha = 0f
    private var lastMissileSide = -1
    private var missileCooldown = 0L
    private var bulletCooldownMs = 0L
    private var gameOver = false
    private var score = 0

    // Player level
    private var multiFireLevel = 1
    private var piercingLevel = 1
    private var shieldLevel = 0
    private var missileLevel = 0
    private var rapidFireLevel = 1

    private val bullets = mutableListOf<Bullet>()
    private val enemyBullets = mutableListOf<Bullet>()
    private val enemies = mutableListOf<Enemy>()
    private val rockets = mutableListOf<Rocket>()
    private val stars = mutableListOf<Star>()
    private val explosions = mutableListOf<Explosion>()
    private val rocketTrails = mutableListOf<Pair<Float, Float>>()
    private val pickups = mutableListOf<Pickup>()
    private val playerMissiles = mutableListOf<PlayerMissile>()

    private data class Bullet(var x: Float, var y: Float, val dy: Float = -15f, var life: Int = 1)
    private data class Star(var x: Float, var y: Float, val radius: Float, val speed: Float)
    private data class Rocket(var x: Float, var y: Float, var angle: Float, val trail: MutableList<Pair<Float, Float>> = mutableListOf())
    private data class Explosion(var x: Float, var y: Float, var timer: Int = 12)
    private data class Pickup(
        val x: Float,
        var y: Float,
        val type: Int,
        var hue: Float = Random.nextFloat() * 360f,
    )
    private data class PlayerMissile(
        var x: Float,
        var y: Float,
        var angle: Float,
        var ttl: Long = 90000L,
        var target: Enemy? = null,
        var recheckCooldown: Long = 0L,
        var side: Int, // -1 = left, 1 = right
        val trail: MutableList<Pair<Float, Float>> = mutableListOf()
    )

    private var lastLogicTime = 0L
    private val logicStepMs = 16L

    private var waveTimer = 0L
    private var currentWave = 0
    private var enemiesLeftInWave = 0
    private var currentWaveType = ""

    init {
        for (i in 0 until 50) {
            stars.add(Star(Random.nextFloat() * 1080f, Random.nextFloat() * 1920f, Random.nextFloat() * 2f + 1f, Random.nextFloat() * 2f + 0.5f))
        }

        val colorAttrs = intArrayOf(
            com.google.android.material.R.attr.colorPrimaryVariant,
            com.google.android.material.R.attr.colorSecondary
        )
        val ta = context.obtainStyledAttributes(colorAttrs)
        try {
            playerPaint.color = ta.getColor(0, Color.CYAN)
            enemyPaint.color = ta.getColor(0, Color.CYAN)
            colorSecondary = ta.getColor(1, Color.GREEN)
        } finally {
            ta.recycle()
        }

        Choreographer.getInstance().postFrameCallback(this)
        lastLogicTime = System.nanoTime()
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        viewWidth = w.toFloat()
        viewHeight = h.toFloat()
        // Kinda hacky way to center things, but I'd rather do this here than in update(), since it can't be in init() as the screen size isn't initialized at that point.
        playerX = viewWidth / 2f
        retryRect.set(viewWidth / 2f - 120f, viewHeight / 2f + 60f, viewWidth / 2f + 120f, viewHeight / 2f + 130f)
    }

    override fun doFrame(frameTimeNanos: Long) {
        if (!gameOver) {
            val now = System.nanoTime()
            while ((now - lastLogicTime) / 1_000_000 >= logicStepMs) {
                update(logicStepMs)
                lastLogicTime += logicStepMs * 1_000_000
            }
            invalidate()
            Choreographer.getInstance().postFrameCallback(this)
        }
    }

    private fun update(deltaMs: Long) {
        stars.forEach {
            it.y += it.speed * deltaMs / 16f
            if (it.y > viewHeight) {
                it.y = 0f
                it.x = Random.nextFloat() * viewWidth
            }
        }

        // Update shield recharge timer and flash animation
        if (shieldRechargeTimer > 0) {
            shieldRechargeTimer -= deltaMs
            if (shieldRechargeTimer <= 0) {
                shieldRechargeTimer = 0
                shieldFlashAlpha = 1f // trigger visual flash on recharge
            }
        }

        if (shieldFlashAlpha > 0f) {
            shieldFlashAlpha -= deltaMs / 300f
            if (shieldFlashAlpha < 0f) shieldFlashAlpha = 0f
        }

        rockets.forEach { rocket ->
            rocket.trail.add(0, rocket.x to rocket.y)
            if (rocket.trail.size > 20) {
                rocket.trail.removeLast()
            }
        }

        explosions.forEach { it.timer-- }
        explosions.removeIf { it.timer <= 0 }

        bullets.forEach { it.y += it.dy * deltaMs / 16f }
        bullets.removeIf { it.y < 0 || it.life <= 0 }

        bulletCooldownMs -= deltaMs
        if (isTouching && bulletCooldownMs <= 0) {
            val baseCooldown = 450f
            var multiplier = 1f
            for (level in 2..rapidFireLevel) {
                val reduction = ((36 - level * 1.2f).coerceAtLeast(4f)) / 100f
                multiplier *= (1f - reduction)
            }
            bulletCooldownMs = max(50L, (baseCooldown * multiplier).toLong())

            val baseY = viewHeight - 100f
            val spacing = 10f
            val count = multiFireLevel

            for (i in 0 until count) {
                val offset = (i - (count - 1) / 2f) * spacing
                bullets.add(Bullet(playerX + offset, baseY))
            }
        }

        enemies.forEach {
            it.update(deltaMs)
            it.x = max(20f, min(it.x, viewWidth - 20f))
            if (it.y > viewHeight + 100f) it.y = -40f // respawn at top
        }

        pickups.forEach { 
            it.y += 2.5f * deltaMs / 16f
            it.hue = (it.hue + deltaMs * 0.01f) % 360f
        }
        pickups.removeIf { it.y > viewHeight - 40f }

        rockets.forEach {
            val targetAngle = atan2(viewHeight - 100f - it.y, playerX - it.x)
            it.angle += ((targetAngle - it.angle + PI).mod(2 * PI) - PI).toFloat() * 0.1f
            it.x += cos(it.angle) * 6f
            it.y += sin(it.angle) * 6f
        }
        rockets.removeIf { it.x < 0 || it.x > viewWidth || it.y < 0 || it.y > viewHeight }

        enemyBullets.forEach { it.y += it.dy * deltaMs / 16f }
        enemyBullets.removeIf { it.y > viewHeight }

        updatePlayerMissiles(deltaMs)

        checkCollisions()
        spawnEnemies(deltaMs)
    }

    private fun checkCollisions() {
        val pickupIter = pickups.iterator()
        while (pickupIter.hasNext()) {
            val p = pickupIter.next()
            if (hypot(playerX - p.x, viewHeight - 100f - p.y) < 40f) {
                when (p.type) {
                    0 -> { // Multi-fire
                        if (multiFireLevel < 4) {
                            multiFireLevel++
                        } else {
                            applyRandomPowerupExcept(0)
                        }
                    }
                    1 -> shieldLevel++
                    2 -> if (missileLevel < 8) missileLevel++
                    3 -> if (rapidFireLevel < 30) rapidFireLevel++
                    4 -> if (piercingLevel < 15) piercingLevel++
                }
                pickupIter.remove()
            }
        }

        val enemyIter = enemies.iterator()
        while (enemyIter.hasNext()) {
            val enemy = enemyIter.next()
            if (hypot(playerX - enemy.x, viewHeight - 100f - enemy.y) < 40f) {
                if (shieldLevel > 0 && shieldRechargeTimer <= 0) {
                    shieldRechargeTimer = calculateShieldRechargeTime()
                    enemyIter.remove()
                    explosions.add(Explosion(enemy.x, enemy.y))
                    continue
                } else {
                    explosions.add(Explosion(playerX, viewHeight - 100f))
                    gameOver = true
                    return
                }
            }
            for (b in bullets) {
                if (hypot(b.x - enemy.x, b.y - enemy.y) < 30f) {
                    explosions.add(Explosion(enemy.x, enemy.y))
                    enemyIter.remove()
                    score += 10
                    b.life--

                    if (Random.nextFloat() < 0.03f) {
                        val type = Random.nextInt(5) // 5 pickup types
                        val hue = Random.nextFloat() * 360f
                        pickups.add(Pickup(enemy.x, enemy.y, type, hue))
                    }
                    break
                }
            }
        }

        val bulletIter = enemyBullets.iterator()
        while (bulletIter.hasNext()) {
            val b = bulletIter.next()
            val dy = b.y - (viewHeight - 100f)
            val dx = b.x - playerX
            val dist = hypot(dx, dy)
            val hitRadius = if (shieldLevel > 0 && shieldRechargeTimer <= 0) 60f else 20f

            if (dist < hitRadius) {
                if (shieldLevel > 0 && shieldRechargeTimer <= 0) {
                    shieldRechargeTimer = calculateShieldRechargeTime()
                    bulletIter.remove()
                    explosions.add(Explosion(b.x, b.y))
                } else {
                    explosions.add(Explosion(playerX, viewHeight - 100f))
                    gameOver = true
                    return
                }
            }
        }

        val rocketIter = rockets.iterator()
        while (rocketIter.hasNext()) {
            val rocket = rocketIter.next()
            val dy = viewHeight - 100f - rocket.y
            val dx = playerX - rocket.x
            val dist = hypot(dx, dy)
            val hitRadius = if (shieldLevel > 0 && shieldRechargeTimer <= 0) 60f else 30f

            if (dist < hitRadius) {
                if (shieldLevel > 0 && shieldRechargeTimer <= 0) {
                    shieldRechargeTimer = calculateShieldRechargeTime()
                    rocketIter.remove()
                    explosions.add(Explosion(rocket.x, rocket.y))
                    continue
                } else {
                    explosions.add(Explosion(playerX, viewHeight - 100f))
                    gameOver = true
                    return
                }
            }

            for (b in bullets) {
                if (hypot(b.x - rocket.x, b.y - rocket.y) < 20f) {
                    explosions.add(Explosion(rocket.x, rocket.y))
                    rocketIter.remove()
                    break
                }
            }
        }

        val missileIter = playerMissiles.iterator()
        while (missileIter.hasNext()) {
            val missile = missileIter.next()
            val enemyHit = enemies.firstOrNull { enemy ->
                hypot(missile.x - enemy.x, missile.y - enemy.y) < 30f
            }

            if (enemyHit != null) {
                explosions.add(Explosion(enemyHit.x, enemyHit.y))
                enemies.remove(enemyHit)
                missileIter.remove()
                score += 10

                if (Random.nextFloat() < 0.5f) {
                    val type = Random.nextInt(5)
                    val hue = Random.nextFloat() * 360f
                    pickups.add(Pickup(enemyHit.x, enemyHit.y, type, hue))
                }
            }
        }
    }

    private fun updatePlayerMissiles(deltaMs: Long) {
        // Missile cooldown and launch
        missileCooldown -= deltaMs
        if (missileLevel > 0 && missileCooldown <= 0) {
            val cooldown = when (missileLevel) {
                1 -> 20000L
                2 -> 15000L
                3 -> 12000L
                4 -> 20000L
                5 -> 18000L
                6 -> 17000L
                7 -> 16000L
                else -> 15000L
            }

            val baseY = viewHeight - 100f
            if (missileLevel >= 4) {
                // fire both sides
                playerMissiles.add(PlayerMissile(playerX - 20f, baseY, -PI.toFloat() / 2f, side = -1))
                playerMissiles.add(PlayerMissile(playerX + 20f, baseY, -PI.toFloat() / 2f, side = 1))
            } else {
                lastMissileSide *= -1
                val offsetX = 20f * lastMissileSide
                playerMissiles.add(PlayerMissile(playerX + offsetX, baseY, -PI.toFloat() / 2f, side = lastMissileSide))
            }

            missileCooldown = cooldown
        }

        // Update missiles
        val lockedEnemies = playerMissiles.mapNotNull { it.target }.toSet()
        val availableTargets = enemies.filter { it !in lockedEnemies }

        playerMissiles.forEach { missile ->
            missile.ttl -= deltaMs
            if (missile.ttl <= 0) return@forEach

            // Add current position to trail
            missile.trail.add(0, missile.x to missile.y)
            if (missile.trail.size > 20) {
                missile.trail.removeLast()
            }

            if (missile.target == null || !enemies.contains(missile.target)) {
                missile.recheckCooldown -= deltaMs
                if (missile.recheckCooldown <= 0) {
                    val newTarget = availableTargets.minByOrNull {
                        hypot((it.x - missile.x).toDouble(), (it.y - missile.y).toDouble())
                    }
                    if (newTarget != null) {
                        missile.target = newTarget
                    } else {
                        missile.recheckCooldown = 1000L
                    }
                }
            }

            val target = missile.target
            val angleTo = if (target != null) {
                atan2(target.y - missile.y, target.x - missile.x)
            } else missile.angle

            // steer towards target slowly
            missile.angle += ((angleTo - missile.angle + PI).mod(2 * PI) - PI).toFloat() * 0.1f
            missile.x += cos(missile.angle) * 6f
            missile.y += sin(missile.angle) * 6f
        }

        playerMissiles.removeIf { it.ttl <= 0 || it.x < 0 || it.x > viewWidth || it.y < 0 || it.y > viewHeight }
    }

    private fun applyRandomPowerupExcept(excludedType: Int) {
        val types = (0..4).filter { it != excludedType }
        val type = types.random()
        when (type) {
            1 -> shieldLevel++
            2 -> if (missileLevel < 8) missileLevel++
            3 -> if (rapidFireLevel < 30) rapidFireLevel++
            4 -> if (piercingLevel < 15) piercingLevel++
        }
    }

    private fun createCubeIconPath(): Path {
        return Path().apply {
            addRect(-10f, -10f, 10f, 10f, Path.Direction.CW)
        }
    }

    private fun calculateShieldRechargeTime(): Long {
        val base = 60000L     // 60 seconds
        val min = 10000L      // 10 seconds
        val reduction = (1.0 - exp(-shieldLevel / 40.0)).toFloat()
        return (base - (base - min) * reduction).toLong()
    }

    private fun spawnEnemies(deltaMs: Long) {
        waveTimer -= deltaMs
        adaptiveSpawnTimer += deltaMs

        // Passive asteroids
        if (Random.nextFloat() < 0.002f) {
            enemies.add(EnemyAsteroid(Random.nextFloat() * viewWidth, -40f, viewWidth))
        }

        // Setup new wave
        if (enemiesLeftInWave <= 0 && waveTimer <= 0) {
            currentWave++
            currentWaveType = when (currentWave % 3) {
                0 -> "easy"
                1 -> "medium"
                else -> "hard"
            }

            val difficultyBoost = when (currentWaveType) {
                "easy" -> (currentWave * 1.2f).roundToInt()
                "medium" -> (currentWave * 1.5f).roundToInt()
                "hard" -> (currentWave * 1.8f).roundToInt()
                else -> currentWave
            }

            enemiesLeftInWave = 3 + difficultyBoost
            waveTimer = 3000L
            adaptiveSpawnTimer = 0L
            lastEnemyCount = enemies.size
            avgEnemiesPerSecond = 0f
            enemyClearAggression = 0f
        }

        // Adjust aggression every 1s
        if (adaptiveSpawnTimer >= 1000L) {
            val cleared = (lastEnemyCount - enemies.size).coerceAtLeast(0)
            avgEnemiesPerSecond = avgEnemiesPerSecond * 0.7f + cleared * 0.3f
            lastEnemyCount = enemies.size
            adaptiveSpawnTimer = 0L

            // Normalize to 0–1 range (assuming 0 to 6 cleared per second)
            enemyClearAggression = (avgEnemiesPerSecond / 6f).coerceIn(0f, 1f)
        }

        // Spawn enemies in group
        if (enemiesLeftInWave > 0 && enemies.count { it !is EnemyAsteroid } < 10) {
            val baseX = Random.nextFloat() * (viewWidth - 100f) + 50f
            val baseY = -40f
            val spacing = 35f
            val sharedOffset = Random.nextFloat() * 1000f
            val sharedFireTime = Random.nextLong(2000L, 4000L)

            // Dynamically adjust formation size
            val formationBase = when (currentWaveType) {
                "easy" -> 5
                "medium" -> 3
                "hard" -> 1
                else -> 3
            }

            // Scale formation by aggression (max +2)
            val dynamicBonus = (enemyClearAggression * 2).roundToInt()
            val formationSize = (formationBase + dynamicBonus).coerceAtMost(enemiesLeftInWave)

            for (i in 0 until formationSize) {
                val offsetX = (i - (formationSize - 1) / 2f) * spacing
                val x = baseX + offsetX

                val enemy = when (currentWaveType) {
                    "easy" -> EnemyEasy(x, baseY)
                    "medium" -> EnemyMedium(x, baseY, sharedOffset, sharedFireTime) { enemyBullets.add(it) }
                    "hard" -> {
                        val hardEnemiesSoFar = enemies.count { it is EnemyHard }
                        if (hardEnemiesSoFar >= 2) {
                            EnemyMedium(x, baseY, sharedOffset, sharedFireTime) { enemyBullets.add(it) }
                        } else {
                            EnemyHard(x, baseY, { rockets.add(it) }, sharedOffset, sharedFireTime)
                        }
                    }
                    else -> EnemyEasy(x, baseY)
                }

                enemies.add(enemy)
                enemiesLeftInWave--
            }
        }
    }

    private fun resetGame() {
        bullets.clear()
        enemyBullets.clear()
        enemies.clear()
        rockets.clear()
        explosions.clear()
        rocketTrails.clear()
        playerMissiles.clear()
        pickups.clear()

        // Reset upgrades
        multiFireLevel = 1
        piercingLevel = 1
        shieldLevel = 0
        missileLevel = 0
        rapidFireLevel = 1

        // Reset gameplay state
        score = 0
        currentWave = 0
        enemiesLeftInWave = 0
        gameOver = false
        shieldRechargeTimer = 0L
        shieldFlashAlpha = 0f
        lastMissileSide = -1
        missileCooldown = 0L
        bulletCooldownMs = 0L
        enemyClearAggression = 0f
        adaptiveSpawnTimer = 0L
        lastEnemyCount = 0
        avgEnemiesPerSecond = 0f

        playerX = viewWidth / 2f
        lastLogicTime = System.nanoTime()
        Choreographer.getInstance().postFrameCallback(this)
    }

    override fun onDraw(canvas: Canvas) {
        viewWidth = width.toFloat()
        viewHeight = height.toFloat()

        canvas.drawColor(Color.parseColor("#121212"))
        stars.forEach { canvas.drawCircle(it.x, it.y, it.radius, starPaint) }

        val enemyBulletPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
            color = Color.RED
            strokeWidth = 6f // same as player bullets
        }
        enemyBullets.forEach { canvas.drawLine(it.x, it.y, it.x, it.y + 20f, enemyBulletPaint) }

        // Enemy rockets
        rockets.forEach { rocket ->
            rocket.trail.forEachIndexed { index, (x, y) ->
                val alpha = ((1f - index / 20f.toFloat()) * 255).toInt()
                rocketPaint.alpha = alpha
                canvas.drawCircle(x, y, 2f, rocketPaint)
            }
        }
        rocketPaint.alpha = 255

        // Player rockets
        val missilePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
            color = colorSecondary
            style = Paint.Style.STROKE
            strokeWidth = 3f
        }

        playerMissiles.forEach { missile ->
            missile.trail.forEachIndexed { index, (x, y) ->
                val alpha = ((1f - index / 20f.toFloat()) * 255).toInt()
                missilePaint.alpha = alpha
                canvas.drawCircle(x, y, 2f, missilePaint)
            }
        }

        missilePaint.alpha = 255
        playerMissiles.forEach { missile ->
            canvas.drawCircle(missile.x, missile.y, 10f, missilePaint)
        }

        explosions.forEach {
            val radius = 40f * (1f - it.timer / 12f.toFloat())
            val alpha = (255 * (it.timer / 12f.toFloat())).toInt()
            val paint = Paint().apply {
                color = Color.YELLOW
                this.alpha = alpha
                style = Paint.Style.STROKE
                strokeWidth = 3f
            }
            canvas.drawCircle(it.x, it.y, radius, paint)
        }

        bullets.forEach { canvas.drawLine(it.x, it.y, it.x, it.y - 20f, bulletPaint) }
        enemies.forEach { it.draw(canvas, enemyPaint) }
        rockets.forEach { canvas.drawCircle(it.x, it.y, 10f, rocketPaint) }

        // Draw pickups
        pickups.forEach { pickup ->
            // Draw cube (filled rect with outline)
            val size = 30f
            val left = pickup.x - size / 2f
            val top = pickup.y - size / 2f
            val right = pickup.x + size / 2f
            val bottom = pickup.y + size / 2f

            val hsv = floatArrayOf(pickup.hue, 1f, 1f)
            val fillPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
                color = Color.HSVToColor(hsv)
                style = Paint.Style.FILL
            }
            val outlinePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
                color = Color.WHITE
                style = Paint.Style.STROKE
                strokeWidth = 2f
            }

            canvas.drawRect(left, top, right, bottom, fillPaint)
            canvas.drawRect(left, top, right, bottom, outlinePaint)

            // Draw icon
            val iconPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
                color = Color.WHITE
                strokeWidth = 3f
                style = Paint.Style.STROKE
            }

            canvas.save()
            canvas.translate(pickup.x, pickup.y)
            canvas.rotate(-45f)

            when (pickup.type) {
                0 -> { // Multi-fire: two parallel lines
                    canvas.drawLine(-8f, -10f, -8f, 10f, iconPaint)
                    canvas.drawLine(8f, -10f, 8f, 10f, iconPaint)
                }
                1 -> { // Shield: quarter circle
                    val path = Path()
                    path.addArc(RectF(-10f, -10f, 10f, 10f), -90f, 90f)
                    canvas.drawPath(path, iconPaint)
                }
                2 -> { // Missiles: circle + trail
                    canvas.drawCircle(0f, 0f, 4f, iconPaint)
                    canvas.drawLine(-6f, 6f, -2f, 2f, iconPaint)
                }
                3 -> { // Rapid fire: two lines in succession
                    canvas.drawLine(-5f, -10f, -5f, 10f, iconPaint)
                    canvas.drawLine(5f, -10f, 5f, 10f, iconPaint)
                }
                4 -> { // Piercing bullets: arrow head
                    val path = Path()
                    path.moveTo(-8f, 10f)
                    path.lineTo(0f, -10f)
                    path.lineTo(8f, 10f)
                    canvas.drawPath(path, iconPaint)
                }
            }

            canvas.restore() 
        }

        if (!gameOver) {
            // Draw player
            val baseY = viewHeight - 100f
            val safeX = max(30f, min(playerX, viewWidth - 30f))
            playerX = safeX
            val path = Path().apply {
                moveTo(safeX, baseY - 30f)
                lineTo(safeX - 30f, baseY + 30f)
                lineTo(safeX + 30f, baseY + 30f)
                close()
            }
            canvas.drawPath(path, playerPaint)

            // Draw shield
            if (shieldLevel > 0 && shieldRechargeTimer <= 0) {
                val baseColor = colorSecondary
                val shieldPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
                    color = baseColor
                    style = Paint.Style.STROKE
                    strokeWidth = 6f
                    alpha = (180 + shieldFlashAlpha * 75f).toInt().coerceAtMost(255)
                }
                canvas.drawCircle(playerX, viewHeight - 100f, 60f, shieldPaint)
            }
        } else {
            canvas.drawText("Game Over", viewWidth / 2f, viewHeight / 2f - 60f, textPaint)
            canvas.drawText("Score: $score", viewWidth / 2f, viewHeight / 2f + 10f, textPaint)
            canvas.drawText("Tap to restart", retryRect.centerX(), retryRect.centerY() + 16f, retryTextPaint)
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (gameOver && event.action == MotionEvent.ACTION_DOWN) {
            resetGame()
            return true
        }

        when (event.action) {
            MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
                playerX = max(30f, min(event.x, width - 30f))
                isTouching = true
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> isTouching = false
        }
        return true
    }

    private interface Enemy {
        var x: Float
        var y: Float
        fun update(deltaMs: Long)
        fun draw(canvas: Canvas, paint: Paint)
    }

    private class EnemyAsteroid(
        override var x: Float,
        override var y: Float,
        private val screenWidth: Float
    ) : Enemy {
        private var vx = Random.nextFloat() * 2f - 1f
        private val vy = Random.nextFloat() * 2f + 2f
        private var angle = Random.nextFloat() * 360f
        private val rotationSpeed = Random.nextFloat() * 2f * if (Random.nextBoolean()) 1 else -1

        override fun update(deltaMs: Long) {
            x += vx * deltaMs / 16f
            y += vy * deltaMs / 16f
            angle = (angle + rotationSpeed * deltaMs / 16f) % 360f

            if (x < 20f || x > screenWidth - 20f) {
                vx = -vx
                x = max(20f, min(x, screenWidth - 20f))
            }
        }

        override fun draw(canvas: Canvas, paint: Paint) {
            canvas.save()
            canvas.rotate(angle, x, y)
            val path = Path().apply {
                moveTo(x - 20f, y)
                lineTo(x - 10f, y - 15f)
                lineTo(x + 10f, y - 15f)
                lineTo(x + 20f, y)
                lineTo(x + 10f, y + 15f)
                lineTo(x - 10f, y + 15f)
                close()
            }
            canvas.drawPath(path, paint)
            canvas.restore()
        }
    }

    private class EnemyEasy(override var x: Float, override var y: Float) : Enemy {
        private val offset = Random.nextFloat() * 1000f
        override fun update(deltaMs: Long) {
            y += 2f * deltaMs / 16f
            x += sin((y + offset) / 50f) * 2f
        }
        override fun draw(canvas: Canvas, paint: Paint) {
            val path = Path().apply {
                moveTo(x, y - 20f)
                lineTo(x + 20f, y)
                lineTo(x, y + 20f)
                lineTo(x - 20f, y)
                close()
            }
            canvas.drawPath(path, paint)
        }
    }

        private class EnemyMedium(
        override var x: Float,
        override var y: Float,
        private val offset: Float,
        private var fireTimer: Long,
        val fireEnemyBullet: (Bullet) -> Unit
    ) : Enemy {
        override fun update(deltaMs: Long) {
            y += 2.5f * deltaMs / 16f
            x += sin((y + offset) / 40f) * 3f

            fireTimer -= deltaMs
            if (fireTimer <= 0) {
                fireEnemyBullet(Bullet(x, y + 30f, dy = 10f))
                fireTimer = Random.nextLong(3000L, 6000L)
            }
        }

        override fun draw(canvas: Canvas, paint: Paint) {
            val path = Path().apply {
                moveTo(x, y - 25f)
                lineTo(x + 15f, y)
                lineTo(x, y + 25f)
                lineTo(x - 15f, y)
                close()
            }
            canvas.drawPath(path, paint)
        }
    }

    private class EnemyHard(
        override var x: Float,
        override var y: Float,
        val fireRocket: (Rocket) -> Unit,
        private val offset: Float = Random.nextFloat() * 1000f,
        private var fireTimer: Long = Random.nextLong(2000L, 5000L)
    ) : Enemy {
        private var cooldown = 0L
        private var firing = false

        override fun update(deltaMs: Long) {
            if (firing) {
                cooldown += deltaMs
                if (cooldown > 500 && cooldown < 1300) {
                    fireRocket(Rocket(x, y - 30f, -PI.toFloat() / 2))
                    cooldown = 1300
                } else if (cooldown > 2000) {
                    cooldown = 0L
                    fireTimer = Random.nextLong(15000L, 25000L)
                    firing = false
                }
                return
            }

            y += 3f * deltaMs / 16f
            x += sin((y + offset) / 25f) * 4f
            fireTimer -= deltaMs
            if (fireTimer <= 0) {
                firing = true
                cooldown = 0L
            }
        }

        override fun draw(canvas: Canvas, paint: Paint) {
            val path = Path().apply {
                moveTo(x, y - 25f)
                lineTo(x + 10f, y - 10f)
                lineTo(x + 20f, y + 10f)
                lineTo(x, y + 25f)
                lineTo(x - 20f, y + 10f)
                lineTo(x - 10f, y - 10f)
                close()
            }
            canvas.drawPath(path, paint)
        }
    }
}
