Assemble = {}
class("Assemble").extends(BaseScene)
local scene = Assemble

local font = Graphics.font.new('assets/fonts/Mini Sans 2X')
local fontMed = Graphics.font.new('assets/fonts/onyx_9')

local allButtons = { "A", "B", "DOWN", "LEFT", "RIGHT", "UP" }

function scene:popCode(button)
    if #scene.code == 0 then
        return
    end
    scene.menuConfirmSound:stop()
    if scene.tickTimer.paused then
        scene.droneParts = scene:loadDrone(1, #scene.code)
        scene.tickTimer:start()
        scene.progressBar:setVisible(true)
    end
    if button == scene.code[1] then
        table.remove(scene.code, 1)
        scene.tickTimer:reset()
        scene.dronePartIndex = scene.dronePartIndex + 1

        local particle = ParticlePoly(200, 185)
        particle:setThickness(2)
        particle:setSize(1, 2)
        particle:setSpeed(1, 3)
        particle:setColour(Graphics.kColorXOR)
        particle:add(5)
        scene.dY = 5
        scene.menuConfirmSound:play(1)
    else
        self.buttonTimeout = self.buttonTimeout - 5
        scene.code[1] = scene:randomButton()
        screenShake(100, 5)
    end
end

scene.inputHandler = {
    AButtonDown = function()
        if #scene.code == 0 then
            scene.menuConfirmSound:play(1)
            Noble.transition(Game, nil, Noble.Transition.SpotlightMask)
        else
            scene:popCode("A")
        end
    end,
    BButtonDown = function() scene:popCode("B") end,
    downButtonDown = function() scene:popCode("DOWN") end,
    leftButtonDown = function() scene:popCode("LEFT") end,
    rightButtonDown = function() scene:popCode("RIGHT") end,
    upButtonDown = function() scene:popCode("UP") end,
}

function scene:randomButton()
    local button = allButtons[math.random(1, #allButtons)]

    return button
end

function scene:drawBackground()
end

local screwDriver = Graphics.image.new('assets/sprites/assemble/sd.png')
local solder = Graphics.image.new('assets/images/solder.png')

function scene:loadButtons()
    local buttons = {}
    for i = 1, #allButtons do
        local image = Graphics.image.new('assets/sprites/buttons/' .. allButtons[i] .. '.png')
        buttons[allButtons[i]] = image
    end
    return buttons
end

function scene:loadDrone(id, parts)
    local drone = {}
    for i = 1, parts do
        local image = Graphics.image.new('assets/sprites/assemble/' .. id .. '/' .. i .. '.png')
        if image ~= nil then
            table.insert(drone, image)
        end
    end

    return drone
end

function scene:setValues()
    scene.code = {}
    for i = 1, 9 do
        table.insert(scene.code, scene:randomButton())
    end

    scene.difficulty = Noble.Settings.get("difficulty")

    scene.buttons = scene:loadButtons()
    scene.droneParts = {}
    scene.dronePartIndex = 0
    scene.dY = 5

    scene.buttonTimeout = 100

    scene.timeToClick = DifficultySettings[scene.difficulty].assebleTime

    scene.menuConfirmSound = playdate.sound.fileplayer.new("assets/audio/confirm")

    scene.musicEnabled = Noble.Settings.get("music")

    scene.levelAudio = playdate.sound.fileplayer.new("assets/audio/assemble")
    scene.levelAudio:setVolume(0.7)
end

function scene:init()
    scene.super.init(self)
    scene:setValues()

    scene.progressBar = ProgressBar(200, 175, 50, 5)
    scene.progressBar:set(self.buttonTimeout)
    scene.progressBar:setVisible(false)

    scene.tickTimer = playdate.timer.new(scene.timeToClick, self.buttonTimeout, 0, playdate.easingFunctions.linear)
    scene.tickTimer.updateCallback = function(timer)
        scene.buttonTimeout = timer.value
        scene.progressBar:set(scene.buttonTimeout)
    end
    scene.tickTimer.timerEndedCallback = function()
        scene.buttonTimeout = 0
    end
    scene.tickTimer:pause()
end

function scene:start()
    scene.super.start(self)
    

    self.optionsMenu:addMenuItem("Main Menu", function() Noble.transition(Menu) end)
    Noble.showFPS = false
    if scene.musicEnabled then
        scene.levelAudio:play(0)
    end
end

function scene:enter()
    scene.super.enter(self)
    scene.buttonTimeout = 100

    Noble.Input.setHandler(scene.inputHandler)
    local text =
    [[The drone is assembled and operational. We are ready for the mission.

An enemy tank is confirmed in the field. It threatens our advance.

Your task: eliminate the target. Clear the path for our assault units.

This operation is crucial. Execute with precision. Command out.]]

    self.dialogue = pdDialogueBox(text, 390, 46)
    -- self.dialogue:setPadding(4)
end

local elapsedTime = 0
function scene:update()
    scene.super.update(self)

    elapsedTime = elapsedTime + 1 / playdate.display.getRefreshRate()
    local sddy = 0
    local sdy = 0
    local sddx = 0

    if #scene.code == 0 then
        if self.dialogue.enabled ~= true then
            Noble.Input.setHandler(self.dialogue:getInputHandlers())
            function self.dialogue:onClose()
                Noble.Transition.setDefaultProperties(Noble.Transition.SpotlightMask, {
                    x = 325,
                    y = 95,
                    xEnd = 96,
                    yEnd = 100,
                    invert = false
                })
                scene.menuConfirmSound:play(1)
                Noble.transition(Game, nil, Noble.Transition.SpotlightMask)
            end

            self.dialogue:enable()
            return
        else
            scene.droneParts[#scene.droneParts]:draw(100, 20)
            local dy = 1 * math.sin(10 * elapsedTime)

            self.dialogue:update()
            self.dialogue:draw(5, 186 + dy)
        end

        self.progressBar:remove()
        self.tickTimer:remove()
    end

    if #scene.code ~= 0 then -- TODO: this is a hack. no, it's not. it's a SHIT. Why i am do this? What i do with my life?
        sddy = 4 * math.sin(10 * elapsedTime)
        sdy = 4 * math.sin(7 * elapsedTime)
        sddx = 2 * math.cos(5 * elapsedTime)
    end

    screwDriver:draw(300 + sddx, 100 + sddy)
    solder:draw(0, 100 + sdy)

    if #scene.code == 0 then
        return
    end

    if scene.tickTimer.paused then
        Noble.Text.draw("Assemble the drone!", 200, 110, Noble.Text.ALIGN_CENTER, false, font)
    end

    if scene.buttonTimeout <= 0 then
        Noble.Text.draw("Fuck!", 200, 110, Noble.Text.ALIGN_CENTER, false, font)
        self.progressBar:remove()
        self.tickTimer:remove()
        screenShake(100, 5)
        Noble.Input.setEnabled(false)
        playdate.timer.performAfterDelay(2500, function() -- Return to the start after failure
            Noble.Input.setEnabled(true)
            Noble.transition(DroneCardSelector, nil, Noble.Transition.SpotlightMask);
        end)
        return
    end

    if scene.droneParts ~= nil and scene.dronePartIndex ~= nil and scene.dronePartIndex > 0 and #scene.droneParts > 0 then
        scene.droneParts[scene.dronePartIndex]:draw(100, 20)
    end

    Graphics.drawLine(180, 185, 192, 185)
    Graphics.drawLine(208, 185, 220, 185)

    if scene.dY > 0 then
        scene.dY = self.dY - 0.5
    end

    for i = 1, #scene.code do
        local button = scene.buttons[scene.code[i]]

        local first = 1
        if #scene.code == 1 then
            first = 0
        end
        local t = (i - 1) / (#scene.code - first)
        local opaque = playdate.math.lerp(1, 0.3, t) --TODO: not the best solution

        local y = 185 + ((i - 1) * 16) - 8 + scene.dY

        button:drawFaded(192, y, opaque, playdate.graphics.image.kDitherTypeBayer2x2)
    end
end

function scene:exit()
    scene.super.exit(self)
    scene.levelAudio:stop()
    Noble.showFPS = false
end

function scene:finish()
    scene.super.finish(self)
    playdate.display.setScale(1)
end
