package net.torvald.terrarum.modulebasegame.ui

import com.badlogic.gdx.Input.Keys
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import net.torvald.terrarum.*
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.itemproperties.Item
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
import net.torvald.terrarum.modulebasegame.gameitems.ItemTextSignCopper
import net.torvald.terrarum.ui.*
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import net.torvald.unicode.TIMES
import net.torvald.unicode.getKeycapPC
import kotlin.math.roundToInt

/**
 * Created by minjaesong on 2024-03-22.
 */
class UIEngravingTextSign : UICanvas(
    toggleKeyLiteral = "control_key_inventory",
    toggleButtonLiteral = "control_gamepad_start"
) {

    private var panelZoom = 4f
    init {
        CommonResourcePool.addToLoadingList("spritesheet:copper_sign") {
            TextureRegionPack(ModMgr.getGdxFile("basegame", "sprites/fixtures/text_sign_glass_copper.tga"), TILE_SIZE, 2*TILE_SIZE)
        }
        CommonResourcePool.loadAll()
    }

    private val signSheet = CommonResourcePool.getAsTextureRegionPack("spritesheet:copper_sign")

    override var width = Toolkit.drawWidth
    override var height = App.scr.height

    fun getPlayerInventory(): ActorInventory = INGAME.actorNowPlaying!!.inventory

    private val row0 = App.scr.halfh + 48
    private val row1 = row0 + 60
    private val row2 = row1 + 40

    private val row3 = maxOf(UIInventoryFull.yEnd.toInt() - 20 - 36, row2 + 64)

    private val goButtonWidth = 180

    private val internalWidth = 480
    private val drawX = (Toolkit.drawWidth - internalWidth) / 2
    private val inputWidth = 350
    private val spinnerWidth = ControlPanelCommon.CONFIG_SPINNER_WIDTH
    private val ingredientsWidth = UIItemInventoryElemSimple.height * 3 + 16
    private val inputX = drawX + internalWidth - inputWidth

    private val textInput = UIItemTextLineInput(this, inputX - 1, row0, inputWidth).also {
        it.textCommitListener = { text ->
            val textLen = App.fontGame.getWidth(text) + 4
            val panelCountMin = (textLen / TILE_SIZEF).ceilToInt()

            updateMinimumLen(panelCountMin)
            panelCount = panelCountSpinner.value.toInt()

            updatePanelText(text, panelCount)
        }
    }

    private val COPPER_BULB = "item@basegame:35"
    private val ROCK_TILE = Block.STONE_TILE_WHITE
    private val GLASS = Block.GLASS_CRUDE


    private val backdropColour = Color(0xffffff_c8.toInt())

    private var fboText = FrameBuffer(Pixmap.Format.RGBA8888, 1, 1, false)
    private var fboBatch = SpriteBatch()
    private var fboCamera = OrthographicCamera(1f, 1f)

    private fun updateMinimumLen(mlen0: Int) {
        val mlen = mlen0.coerceAtLeast(2).toDouble()
        val delta = maxOf(panelCount.toDouble(), mlen) - panelCount.toDouble()
        panelCountSpinner.changeValueBy(delta.toInt())
        setIngredient(panelCountSpinner.value.toInt())
    }

    private fun updatePanelText(text: String, panelCount: Int) {
        fboText.dispose()
        fboText = FrameBuffer(Pixmap.Format.RGBA8888, panelCount*TILE_SIZE, 2*TILE_SIZE, false)
        fboText.colorBufferTexture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
        fboCamera.setToOrtho(true, panelCount*TILE_SIZEF, 2*TILE_SIZEF)

        fboText.inAction(fboCamera, fboBatch) {
            gdxClearAndEnableBlend(Color.CLEAR)
            fboBatch.color = Color.WHITE
            fboBatch.inUse { batch ->
                blendNormalStraightAlpha(batch)
                val tw = App.fontGame.getWidth(text)
                App.fontGame.draw(batch, text, 1 + (it.width - tw) / 2, 2)


                blendAlphaMask(batch)
                for (p in 0 until panelCount) {
                    batch.draw(signSheet.get(3, 0), TILE_SIZEF * p, 0f)
                }
            }
        }
    }

    private fun drawPanels(batch: SpriteBatch, xStart: Float, yStart: Float, panelCount: Int) {
        blendNormalStraightAlpha(batch)

        // panels
        batch.color = backdropColour
        for (p in 0 until panelCount) {
            val sprite = signSheet.get(if (p == 0) 0 else if (p == panelCount - 1) 2 else 1, 0)
            batch.draw(sprite, xStart + p * sprite.regionWidth * panelZoom, yStart, sprite.regionWidth * panelZoom, sprite.regionHeight * panelZoom)
        }

        // text
        batch.draw(fboText.colorBufferTexture, xStart, yStart, fboText.width * panelZoom, fboText.height * panelZoom)
    }

    private fun setIngredient(num: Int) {
        ingredients.clear()
        ingredients.add(GLASS, num * 2L)
        ingredients.add(ROCK_TILE, num * 1L)
        ingredients.add(COPPER_BULB, num * 1L)
        ingredientsPanel.rebuild(UIItemCatBar.FILTER_CAT_ALL)
    }

    private fun refreshCraftButtonStatus() {
        val player = getPlayerInventory()
        val canCraft = ingredients.all {
            (player.searchByID(it.itm)?.qty ?: 0L) >= it.qty
        }
        goButton.isEnabled = canCraft
    }

    private val ingredients = FixtureInventory() // this one is definitely not to be changed
    private val ingredientsPanel = UIItemInventoryItemGrid(
        this,
        { ingredients },
        drawX,
        row2,
        3, 1,
        drawScrollOnRightside = false,
        drawWallet = false,
        hideSidebar = true,
        colourTheme = UIItemInventoryCellCommonRes.defaultInventoryCellTheme.copy(
            cellHighlightSubCol = Toolkit.Theme.COL_INACTIVE
        ),
        keyDownFun = { _, _, _, _, _ -> },
        wheelFun = { _, _, _, _, _, _ -> },
        touchDownFun = { _, _, _, _, _ -> },
    ).also {
        it.isCompactMode = true
    }

    private val panelCountSpinner = UIItemSpinner(
        this,
        inputX + inputWidth - ingredientsWidth + 19,
        row2 - 1,
        2, 2, 32, 1,
        spinnerWidth,
        numberToTextFunction = { "${it.toDouble().roundToInt()}" }
    ).also {
        it.selectionChangeListener = { num0 ->
            val num = num0.toInt()
            setIngredient(num)
            refreshCraftButtonStatus()
        }
    }


    private val resetButton = UIItemTextButton(this,
        { Lang["MENU_LABEL_RESET"] }, width / 2 - 24 - goButtonWidth, row3, goButtonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true).also {

        it.clickOnceListener = { _, _ ->
            resetUI()
        }
    }

    private val goButton = UIItemTextButton(this,
        { Lang["GAME_ACTION_CRAFT"] }, width / 2 + 24, row3, goButtonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true).also {

        it.clickOnceListener = { _, _ ->
            val actorInventory = getPlayerInventory()
            val text = textInput.getText()
            val item = ItemTextSignCopper(Item.COPPER_SIGN).makeDynamic(actorInventory).also {
                it.extra["signContent"] = text
                it.extra["signPanelCount"] = panelCount
                it.nameSecondary = "[$panelCount${TIMES}2] $text"
            }

            actorInventory.add(item)

            resetUI()
        }
    }

    private fun resetUI() {
        panelCountSpinner.resetToSmallest()
        textInput.clearText()
        setIngredient(panelCountSpinner.value.toInt())
        refreshCraftButtonStatus()
    }

    override fun show() {
        super.show()
        resetUI()
    }

    init {
        addUIitem(textInput)
        addUIitem(panelCountSpinner)
        addUIitem(ingredientsPanel)
        addUIitem(goButton)
        addUIitem(resetButton)
    }

    private var panelCount = panelCountSpinner.value.toInt()
    override fun updateImpl(delta: Float) {
        panelCount = panelCountSpinner.value.toInt()

        uiItems.forEach { it.update(delta) }
    }

    private val halfSlotOffset = (UIItemInventoryElemSimple.height + UIItemInventoryItemGrid.listGap) / 2
    private val thisOffsetX = UIInventoryFull.INVENTORY_CELLS_OFFSET_X() + UIItemInventoryElemSimple.height + UIItemInventoryItemGrid.listGap - halfSlotOffset

    private val controlHelp: String
        get() = if (App.environment == RunningEnvironment.PC)
            "${getKeycapPC(ControlPresets.getKey("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
        else
            "${App.gamepadLabelStart} ${Lang["GAME_ACTION_CLOSE"]}"

    override fun renderImpl(frameDelta: Float, batch: SpriteBatch, camera: OrthographicCamera) {
        UIInventoryFull.drawBackground(batch, opacity)

        // paint preview
        drawPanels(batch, (width - panelCount * panelZoom * TILE_SIZE).toInt().div(2).toFloat(), height / 4f - 8, panelCount)

        // paint UI elements
        uiItems.forEach { it.render(frameDelta, batch, camera) }

        // paint labels
        batch.color = Color.WHITE

        val controlHintXPos = thisOffsetX + 2f
        blendNormalStraightAlpha(batch)
        App.fontGame.draw(batch, controlHelp, controlHintXPos, UIInventoryFull.yEnd - 20)

        App.fontGame.draw(batch, Lang["CONTEXT_ENGRAVER_TEXT"], drawX, row0)
        Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_OPTIONS_SIZE"], spinnerWidth, panelCountSpinner.posX, row1)
        Toolkit.drawTextCentered(batch, App.fontGame, Lang["GAME_INVENTORY_INGREDIENTS"], ingredientsWidth, ingredientsPanel.posX, row1)

    }

    override fun dispose() {
        fboText.tryDispose()
        fboBatch.tryDispose()
    }


    override fun doOpening(delta: Float) {
        super.doOpening(delta)
        INGAME.pause()
    }

    override fun doClosing(delta: Float) {
        super.doClosing(delta)
        INGAME.resume()
    }

    override fun endOpening(delta: Float) {
        super.endOpening(delta)
    }

    override fun endClosing(delta: Float) {
        super.endClosing(delta)
        resetUI()
    }

}