local calc = require("#Monocle.Calc")
local monocle = require("#Monocle")
local colors = require("#Microsoft.Xna.Framework.Color")

local playerInside = false

local function glitch(glitch, anxiety, duration)
    celeste.Audio.Play("event:/new_content/game/10_farewell/glitch_short", player.Position)
    celeste.Glitch.Value = glitch
    celeste.Distort.Anxiety = anxiety
    wait(duration)
end

local function particleAbsorbBurst(n)
    for i = 1, n do
        engine.Scene:Add(celeste.AbsorbOrb(player.Position))
    end
end

local function heartSlowDown()
    local frameCounter = 0

    monocle.engine.TimeRate = 0.5
    player.Depth = -2000000

    particleAbsorbBurst(25)
    engine.Scene:Flash(colors.White)
    engine.Scene:Shake()
    engine.Scene.FormationBackdrop.Display = true
    engine.Scene.FormationBackdrop.Alpha = 0.6

    while monocle.engine.TimeRate < 1 do
        if frameCounter % 2 == 0 then
            particleAbsorbBurst(1)
        end

        monocle.engine.TimeRate = calc.Approach(monocle.engine.TimeRate, 1, monocle.engine.RawDeltaTime * 0.5)
        frameCounter = frameCounter + 1

        coroutine.yield(0)
    end

    monocle.engine.TimeRate = 1
    player.Depth = 0
end

local function spawnOrbsUntilOnGround(maxTime)
    local frameCounter = 0

    while not player:OnGround(1) and frameCounter < maxTime * 60 do
        if frameCounter % 4 == 0 then
            particleAbsorbBurst(1)
        end

        frameCounter = frameCounter + 1

        coroutine.yield()
    end
end

function onBegin()
    makeUnskippable()

    while not getFlag("gm_heartside_unique_flag") do
        wait(0)
    end

    setFlag("gm_heartside_unique_flag", false)

    local heart = getFirstEntity("FakeHeart")
    local visible = heart and heart.Visible

    while playerInside and visible do
        visible = heart and heart.Visible

        wait(0)
    end

    if playerInside then
        disableRetry()

        heartSlowDown()
        spawnOrbsUntilOnGround(0.4)

        wait(0.1)

        glitch(0.2, 0, 0.35)
        glitch(0.4, 2, 0.35)
        glitch(0.7, 3, 0.3)

        if not player.Dead then
            monocle.engine.TimeRate = 1
            celeste.Glitch.Value = 0
            celeste.Distort.Anxiety = 0
            engine.Scene.FormationBackdrop.Display = false
            engine.Scene.FormationBackdrop.Alpha = 0

            teleportTo(96, 1096, "a-end")
        end
    end
end

function onEnter()
    playerInside = true
end

function onLeave()
    playerInside = false
end