package com.badlogic.drop

import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Screen
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.Gdx.audio
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.Sprite
import com.badlogic.gdx.math.MathUtils
import com.badlogic.gdx.math.Rectangle
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.math.Vector3
import com.badlogic.gdx.utils.ScreenUtils
import ktx.assets.toInternalFile

class GameScreen(val game: Drop) : Screen {
    val camera = OrthographicCamera().apply { setToOrtho(false, 800f, 480f) }

    val backgroundTexture = Texture("background.png")
    val bucketTexture = Texture("bucket.png")
    val dropTexture = Texture("drop.png")
    val dropSound = audio.newSound("drop.mp3".toInternalFile())
    val music = audio.newMusic("music.mp3".toInternalFile()).apply {
        isLooping = true
        volume = 0.5f
    }
    val bucketSprite = Sprite(bucketTexture).apply { setSize(64f, 64f) }
    val touchPos = Vector3()
    val dropSprites = mutableListOf<Sprite>()
    val dropSpeed = -128f
    var dropTimer = 0f
    val bucketRectangle = Rectangle()
    val dropRectangle = Rectangle()
    var dropsGathered = 0

    override fun show() {
        music.play()
    }

    override fun render(delta: Float) {
        input()
        logic()
        draw()
    }

    private fun input() {
        val speed = 4f
        val delta: Float = Gdx.graphics.deltaTime

        if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
            bucketSprite.translateX(speed * delta)
        }
        if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
            bucketSprite.translateX(-speed * delta)
        }

        if (Gdx.input.isTouched) {
            touchPos.set(Gdx.input.x.toFloat(), Gdx.input.y.toFloat(), 0f)
            camera.unproject(touchPos)
            bucketSprite.setCenterX(touchPos.x)
        }
    }

    private fun logic() {
        val worldWidth: Float = camera.viewportWidth
        val worldHeight: Float = camera.viewportHeight
        val bucketWidth: Float = bucketSprite.width
        val bucketHeight: Float = bucketSprite.height
        val delta: Float = Gdx.graphics.deltaTime

        bucketSprite.x = MathUtils.clamp(bucketSprite.x, 0f, worldWidth - bucketWidth)
        bucketRectangle.set(bucketSprite.x, bucketSprite.y, bucketWidth, bucketHeight)

        for (dropSprite in dropSprites.reversed()) {
            val dropWidth: Float = dropSprite.width
            val dropHeight: Float = dropSprite.height

            dropSprite.translateY(dropSpeed * delta * (MathUtils.clamp((dropsGathered.toFloat() + 1f) / 5f, 1f, Float.MAX_VALUE)))
            dropRectangle.set(dropSprite.x, dropSprite.y, dropWidth, dropHeight)

            if (dropSprite.y < -dropHeight) dropSprites.remove(dropSprite)
            else if (bucketRectangle.overlaps(dropRectangle)) {
                dropsGathered++
                dropSprites.remove(dropSprite)
                dropSound.play()
            }
        }

        dropTimer += delta
        if (dropTimer > 1f) {
            dropTimer = 0f
            createDroplet()
        }
    }

    private fun draw() {
        ScreenUtils.clear(Color.BLACK)

        camera.update()
        game.batch.projectionMatrix = camera.combined

        game.batch.begin()
        val worldWidth: Float = camera.viewportWidth
        val worldHeight: Float = camera.viewportHeight
        game.batch.draw(backgroundTexture, 0f, 0f, worldWidth, worldHeight)
        bucketSprite.draw(game.batch)

        game.font.draw(game.batch, "Drops collected: $dropsGathered", 0f, worldHeight)

        for (dropSprite in dropSprites) dropSprite.draw(game.batch)

        game.batch.end()
    }

    private fun createDroplet() {
        val dropWidth = 64f
        val dropHeight = 64f
        val worldWidth: Float = camera.viewportWidth
        val worldHeight: Float = camera.viewportHeight

        val dropSprite = Sprite(dropTexture).apply {
            setSize(dropWidth, dropHeight)
            x = MathUtils.random(0f, worldWidth - dropWidth)
            y = worldHeight
        }
        dropSprites.add(dropSprite)
    }

    override fun resize(width: Int, height: Int) = Unit

    override fun pause() = Unit

    override fun resume() = Unit

    override fun hide() = Unit

    override fun dispose() {
        backgroundTexture.dispose()
        dropSound.dispose()
        music.dispose()
        dropTexture.dispose()
        bucketTexture.dispose()
    }
}
