-- stylua: ignore start
import "control-screen.lua"
-- stylua: ignore end

---@class MainMenu
MainMenu = {
    ---@type { new: fun(settings: Settings): { update: fun(self) } }
    next = nil,
}
local gfx = playdate.graphics

local ScoreFont <const> = FontFullCircle
local TinyFont <const> = NanoSans

--- Take control of playdate.update
--- Will replace playdate.update when the menu is done.
---@param next { new: fun(settings: Settings): { update: fun(self) } }
function MainMenu.start(next)
    MenuMusic:play(0)
    MainMenu.next = next
    playdate.update = function()
        MainMenu:update()
    end
end

local inningCountSelection = 3

function MainMenu:showControls()
    local next = ControlScreen.new(self)
    transitionBetween(MainMenu, next)
end

local function startGame()
    local next = MainMenu.next.new({
        finalInning = inningCountSelection,
        homeTeamSpriteGroup = HomeTeamSpriteGroup,
        awayTeamSpriteGroup = AwayTeamSpriteGroup,
    })
    playdate.resetElapsedTime()
    transitionBetween(MainMenu, next)
    MenuMusic:setPaused(true)
end

---@param baseEaser EasingFunc
---@return EasingFunc
local function pausingEaser(baseEaser)
    --- t: elapsedTime
    --- d: duration
    return function(t, b, c, d)
        local percDone = t / d
        if percDone > 0.9 then
            t = d
        elseif percDone < 0.1 then
            t = 0
        else
            t = (percDone - 0.1) * 1.25 * d
        end
        return baseEaser(t, b, c, d)
    end
end

local animatorX = gfx.animator.new(2000, 30, 350, pausingEaser(playdate.easingFunctions.linear))
animatorX.repeatCount = -1
animatorX.reverses = true

local animatorY = gfx.animator.new(2000, 60, 200, pausingEaser(utils.easingHill))
animatorY.repeatCount = -1
animatorY.reverses = true

---@type number
local crankStartPos

---@generic T
---@param array T[]
---@param crankPosition number
---@return T
local function arrayElementFromCrank(array, crankPosition)
    local i = math.ceil(#array * (crankPosition + 0.001) / 360)
    return array[i]
end

---@type pd_image
local currentLogo

--luacheck: ignore
function MainMenu:update()
    if playdate.buttonJustPressed(playdate.kButtonA) then
        startGame()
        return
    end

    if playdate.buttonJustPressed(playdate.kButtonB) then
        self:showControls()
        return
    end

    playdate.timer.updateTimers()
    crankStartPos = crankStartPos or playdate.getCrankPosition()

    gfx.clear()

    if playdate.getCrankChange() ~= 0 then
        local crankOffset = (crankStartPos - playdate.getCrankPosition()) % 360
        currentLogo = arrayElementFromCrank(Logos, crankOffset).image
        replaceAwayLogo(currentLogo)
    end

    if currentLogo then
        currentLogo:drawScaled(20, C.Center.y + 40, 3)
    end

    if playdate.buttonJustPressed(playdate.kButtonUp) or playdate.buttonJustPressed(playdate.kButtonRight) then
        inningCountSelection = math.min(99, inningCountSelection + 1)
    end
    if playdate.buttonJustPressed(playdate.kButtonDown) or playdate.buttonJustPressed(playdate.kButtonLeft) then
        inningCountSelection = math.max(1, inningCountSelection - 1)
    end

    local logoCenter = 90
    GameLogo:drawCentered(C.Center.x, logoCenter)
    TinyFont:drawTextAligned("a game by Sage", C.Center.x, logoCenter + 35, kTextAlignment.center)

    local promptOffsetX = 120
    ScoreFont:drawTextAligned(
        "Press A to start with <" .. inningCountSelection .. "> innings",
        C.Center.x - promptOffsetX,
        180,
        kTextAlignment.left
    )
    ScoreFont:drawTextAligned("Press B for controls", C.Center.x - promptOffsetX, 198, kTextAlignment.left)

    local ball = {
        x = animatorX:currentValue(),
        y = animatorY:currentValue(),
        z = 6,
        size = 6,
    }

    local ballIsHeld = drawFielder(AwayTeamSpriteGroup[1], ball, 30, 200)
    ballIsHeld = drawFielder(HomeTeamSpriteGroup[2], ball, 350, 200, playdate.graphics.kImageFlippedX) or ballIsHeld

    if not ballIsHeld then
        gfx.setLineWidth(2)

        gfx.setColor(gfx.kColorWhite)
        gfx.fillCircleAtPoint(ball.x, ball.y, ball.size)

        gfx.setColor(gfx.kColorBlack)
        gfx.drawCircleAtPoint(ball.x, ball.y, ball.size)
    end
end
