local tc=love.touch
local gc_setColor,gc_setLineWidth=GC.setColor,GC.setLineWidth
local gc_draw,gc_line=GC.draw,GC.line
local gc_circle,gc_print=GC.circle,GC.print

local SCR,VK=SCR,VK
local GAME,PLAYERS=GAME,PLAYERS
local setFont,mStr=FONT.set,GC.mStr

local noTouch,noKey=false,false
local touchMoveLastFrame=false
local trigGameRate,gameRate
local autoSkip=0
local modeTextPos,modeTextWidK

local replaying
local repRateStrings={[0]="pause",[.125]="0.125x",[.5]="0.5x",[1]="1x",[2]="2x",[5]="5x"}

local scene={}

-- Widget hashmap (key = widget name, value = index)
local widgetHashmap={}
local function widgetWithName(name)
    if #widgetHashmap==0 then widgetHashmap=TABLE.kvSwap(TABLE.extract(scene.widgetList,'name')) end
    return scene.widgetList[widgetHashmap[name]]
end

local function _updateMenuButtons()
    widgetWithName('restart').hide=replaying

    local pos=(GAME.tasUsed or replaying) and 'right' or SETTING.menuPos
    modeTextWidK=math.min(280/TEXTOBJ.modeName:getWidth(),1)
    if SETTING.portrait then
        widgetWithName('restart').y=25-400
        widgetWithName('pause').y=25-400
    else
        widgetWithName('restart').y=25
        widgetWithName('pause').y=25
    end
    if GAME.replaying then
        widgetWithName('pause').x=1195
        modeTextPos=1185-TEXTOBJ.modeName:getWidth()*modeTextWidK
    elseif pos=='right' then
        widgetWithName('restart').x=1125
        widgetWithName('pause').x=1195
        modeTextPos=1115-TEXTOBJ.modeName:getWidth()*modeTextWidK
    elseif pos=='middle' then
        widgetWithName('restart').x=360
        widgetWithName('pause').x=860
        modeTextPos=940
    elseif pos=='left' then
        widgetWithName('restart').x=120
        widgetWithName('pause').x=190
        modeTextPos=1200-TEXTOBJ.modeName:getWidth()*modeTextWidK
    end
end

local speedButtons={'rep0','repP8','repP2','rep1','rep2','rep5'}
local stepButtons={'step','autoSkip'}
local replayButtons=TABLE.combine(speedButtons,stepButtons)
local function _updateRepButtons()
    local L=scene.widgetList
    if replaying or GAME.tasUsed then
        for i=1,#speedButtons do
            widgetWithName(speedButtons[i]).hide=false
        end
        for i=1,#stepButtons do
            widgetWithName(stepButtons[i]).hide=gameRate~=0
        end
        if gameRate==0 then
            widgetWithName('rep0').hide=true
        elseif gameRate==.125 then
            widgetWithName('repP8').hide=true
        elseif gameRate==.5 then
            widgetWithName('repP2').hide=true
        elseif gameRate==1 then
            widgetWithName('rep1').hide=true
        elseif gameRate==2 then
            widgetWithName('rep2').hide=true
        elseif gameRate==5 then
            widgetWithName('rep5').hide=true
        end
    else
        for i=1,#replayButtons do widgetWithName(replayButtons[i]).hide=true end
    end
end
local function _speedUp()
    if gameRate==.125 then gameRate=.5
    elseif gameRate==.5 then gameRate=1
    elseif gameRate==1 then gameRate=2
    elseif gameRate==2 then gameRate=5
    end
    _updateRepButtons()
end
local function _speedDown()
    if gameRate==.5 then gameRate=.125
    elseif gameRate==1 then gameRate=.5
    elseif gameRate==2 then gameRate=1
    elseif gameRate==5 then gameRate=2
    end
    _updateRepButtons()
end
local function _rep0()
    scene.widgetList[1].hide=true
    scene.widgetList[7].hide=false
    gameRate=0
    _updateRepButtons()
end
local function _repP8()
    scene.widgetList[2].hide=true
    gameRate=.125
    _updateRepButtons()
end
local function _repP2()
    scene.widgetList[3].hide=true
    gameRate=.5
    _updateRepButtons()
end
local function _rep1()
    scene.widgetList[4].hide=true
    gameRate=1
    _updateRepButtons()
end
local function _rep2()
    scene.widgetList[5].hide=true
    gameRate=2
    _updateRepButtons()
end
local function _rep5()
    scene.widgetList[6].hide=true
    gameRate=5
    _updateRepButtons()
end
local function _skip(P)
    if P.frameRun<179 then
        trigGameRate=trigGameRate+(179-P.frameRun)
    else
        trigGameRate=trigGameRate+MATH.clamp(P.waiting+P.falling,1,300)
    end
end
local fastForwardObj = GC.newText(FONT.get(40),CHAR.icon.fastForward)
local nextFrameObj = GC.newText(FONT.get(40),CHAR.icon.nextFrame)
local function _updateStepButton()
    local w=PLAYERS[1].waiting+PLAYERS[1].falling
    if (autoSkip==1 and w>1) or (autoSkip>0 and PLAYERS[1].frameRun<178) then
        widgetWithName('step').obj=fastForwardObj
    else
        widgetWithName('step').obj=nextFrameObj
    end
end
local function _step()
    local P=PLAYERS[1]
    if autoSkip>0 then
        _skip(P)
    else
        trigGameRate=trigGameRate+1
    end
end
local function _fullSkipCheck()
    if autoSkip<2 or PLAYERS[1].waiting+PLAYERS[1].falling<=0 then return end
    _step()
end
local function _setAS(v)
    autoSkip=v
    if v==1 then _updateStepButton() end
end
local function _autoSkipDisp()
    return (
        autoSkip==0 and 'No skip' or
        autoSkip==1 and 'Semi-skip' or
        autoSkip==2 and 'Full skip'
    )
end

local function _restart()
    resetGameData(PLAYERS[1].frameRun<240 and 'q')
    noKey=replaying
    noTouch=replaying
    trigGameRate,gameRate=0,1
    _updateRepButtons()
end
local function _checkGameKeyDown(key)
    local k=KEY_MAP.keyboard[key]
    if k then
        if k>0 then
            if noKey then return end
            PLAYERS[1]:pressKey(k)
            VK.press(k)
            _updateStepButton()
            _fullSkipCheck()
            return
        elseif not GAME.fromRepMenu then
            _restart()
            return
        end
    end
    return true-- No key pressed
end

function scene.enter()
    if GAME.init then
        resetGameData()
        GAME.init=false
    end

    replaying=GAME.replaying
    noKey=replaying
    noTouch=not SETTING.VKSwitch or replaying

    if SCN.prev~='depause' and SCN.prev~='pause' then
        trigGameRate,gameRate=0,1
    elseif not replaying then
        if GAME.tasUsed then
            trigGameRate,gameRate=0,0
            autoSkip=1
        else
            trigGameRate,gameRate=0,1
            autoSkip=0
        end
    end

    _updateStepButton()
    _updateRepButtons()
    _updateMenuButtons()

    DiscordRPC.update("Playing "..GAME.curMode.name)
end

scene.mouseDown=NULL
function scene.touchDown(x,y)
    if noTouch then return end

    local t=VK.on(x,y)
    if t then
        PLAYERS[1]:pressKey(t)
        VK.touch(t,x,y)
        _updateStepButton()
        _fullSkipCheck()
    end
end
function scene.touchUp(x,y)
    if noTouch then return end

    local n=VK.on(x,y)
    if n then
        PLAYERS[1]:releaseKey(n)
        VK.release(n)
    end
end
function scene.touchMove()
    if noTouch or touchMoveLastFrame then return end
    touchMoveLastFrame=true

    local L=tc.getTouches()
    for i=#L,1,-1 do
        L[2*i-1],L[2*i]=SCR.xOy:inverseTransformPoint(tc.getPosition(L[i]))
    end
    local keys=VK.keys
    for n=1,#keys do
        local B=keys[n]
        if B.ava then
            local nextKey
            for i=1,#L,2 do
                if (L[i]-B.x)^2+(L[i+1]-B.y)^2<=B.r^2 then
                    nextKey=true
                    break-- goto CONTINUE_nextKey
                end
            end
            if not nextKey then
                PLAYERS[1]:releaseKey(n)
                VK.release(n)
            end
            -- ::CONTINUE_nextKey::
        end
    end
end
function scene.keyDown(key,isRep)
    if replaying then
        if key=='space' then
            if not isRep then
                gameRate=gameRate==0 and 1 or 0
            end
            _updateRepButtons()
        elseif key=='left' then
            if not isRep then
                _speedDown()
            end
        elseif key=='right' then
            if gameRate==0 then
                _step()
            elseif not isRep then
                _speedUp()
            end
        elseif key=='escape' then
            pauseGame()
        end
    else
        if isRep then
            return
        elseif _checkGameKeyDown(key) then
            if GAME.tasUsed then
                if key=='f1' then
                    if not isRep then
                        gameRate=gameRate==0 and .125 or 0
                    end
                    _updateRepButtons()
                elseif key=='f2' then
                    if not isRep then
                        _speedDown()
                    end
                elseif key=='f3' then
                    if gameRate==0 then
                        _step()
                    elseif not isRep then
                        _speedUp()
                    end
                elseif key=='f4' then
                    autoSkip=(autoSkip+1)%3
                end
            end
            if key=='escape' then
                pauseGame()
            end
        end
    end
end
function scene.keyUp(key)
    if noKey then return end
    local k=KEY_MAP.keyboard[key]
    if k then
        if k>0 then
            PLAYERS[1]:releaseKey(k)
            VK.release(k)
        end
    end
end
function scene.gamepadDown(key)
    if noKey then return end
    local k=KEY_MAP.joystick[key]
    if k then
        if k>0 then
            PLAYERS[1]:pressKey(k)
            VK.press(k)
            _updateStepButton()
            _fullSkipCheck()
        else
            _restart()
        end
    elseif key=='back' then
        pauseGame()
    end
end
function scene.gamepadUp(key)
    if noKey then return end
    local k=KEY_MAP.joystick[key]
    if k then
        if k>0 then
            PLAYERS[1]:releaseKey(k)
            VK.release(k)
        end
    end
end

local function _update_common(dt)
    -- Update control
    touchMoveLastFrame=false
    VK.update(dt)

    -- Update players
    for p=1,#PLAYERS do PLAYERS[p]:update(dt) end

    -- Fresh royale target
    if PLAYERS[1].frameRun%120==0 and PLAYERS[1].gameEnv.layout=='royale' then
        freshMostDangerous()
    end

    -- Warning check
    checkWarning(PLAYERS[1],dt)
end
function scene.update(dt)
    trigGameRate=trigGameRate+gameRate
    while trigGameRate>=1 do
        trigGameRate=trigGameRate-1
        _update_common(dt)
        _updateStepButton()
    end
end

local tasText=GC.newText(getFont(100),"TAS")
local function _drawAtkPointer(x,y)
    local t=TIME()
    local a=t*3%1*.8
    t=math.sin(t*20)

    gc_setColor(.2,.7+t*.2,1,.6+t*.4)
    gc_circle('fill',x,y,25,6)

    gc_setColor(0,.6,1,.8-a)
    gc_circle('line',x,y,30*(1+a),6)
end
function scene.draw()
    local tas=GAME.tasUsed
    if tas then
        setFont(100)
        gc_setColor(.4,.4,.4,.5)
        mDraw(tasText,640,360,nil,5)
    end

    local repMode=GAME.replaying or tas

    -- Players
    for p=1,#PLAYERS do
        PLAYERS[p]:draw(repMode)
    end

    -- Virtual keys
    VK.draw()

    -- Attacking & Being attacked
    if PLAYERS[1].gameEnv.layout=='royale' then
        local P=PLAYERS[1]
        gc_setLineWidth(5)
        gc_setColor(.8,1,0,.2)
        for i=1,#P.atker do
            local p=P.atker[i]
            gc_line(p.centerX,p.centerY,P.x+300*P.size,P.y+620*P.size)
        end
        if P.atkMode~=4 then
            if P.atking then
                _drawAtkPointer(P.atking.centerX,P.atking.centerY)
            end
        else
            for i=1,#P.atker do
                local p=P.atker[i]
                _drawAtkPointer(p.centerX,p.centerY)
            end
        end
    end

    -- Mode info & Highscore & Current Rank
    local dy=SETTING.portrait and -390 or 0
    gc_setColor(1,1,1,.82)
    gc_draw(TEXTOBJ.modeName,modeTextPos,10+dy,0,modeTextWidK,1)
    if not replaying then
        local M=GAME.curMode
        if M then
            if M.score and M.records[1] then
                setFont(15)
                gc_setColor(1,1,1,.6)
                gc_print(M.scoreDisp(M.records[1]),modeTextPos,45+dy)
            end
            if M.getRank then
                local R=M.getRank(PLAYERS[1])
                if R and R>0 then
                    setFont(100)
                    local c=RANK_COLORS[R]
                    gc_setColor(c[1],c[2],c[3],.12)
                    mStr(RANK_CHARS[R],640,50+dy)
                end
            end
        end
    end

    -- Replaying
    if replaying or tas then
        setFont(20)
        gc_setColor(1,1,TIME()%.8>.4 and 1 or 0)
        mStr(replaying and text.replaying or text.tasUsing,770,6)
        gc_setColor(1,1,1,.8)
        mStr(("%s   %sf"):format(repRateStrings[gameRate],PLAYERS[1].frameRun),770,31)
    end

    -- Warning
    drawWarning()
end
scene.widgetList={
    WIDGET.newKey   {name='rep0',    x=40, y=50, w=60, code=_rep0,    font=40,          fText=CHAR.icon.pause},          -- 1
    WIDGET.newKey   {name='repP8',   x=105,y=50, w=60, code=_repP8,   font=40,          fText=CHAR.icon.speedOneEights}, -- 2
    WIDGET.newKey   {name='repP2',   x=170,y=50, w=60, code=_repP2,   font=40,          fText=CHAR.icon.speedOneHalf},   -- 3
    WIDGET.newKey   {name='rep1',    x=235,y=50, w=60, code=_rep1,    font=40,          fText=CHAR.icon.speedOne},       -- 4
    WIDGET.newKey   {name='rep2',    x=300,y=50, w=60, code=_rep2,    font=40,          fText=CHAR.icon.speedTwo},       -- 5
    WIDGET.newKey   {name='rep5',    x=365,y=50, w=60, code=_rep5,    font=40,          fText=CHAR.icon.speedFive},      -- 6
    WIDGET.newKey   {name='step',    x=40, y=50, w=60, code=_step,    font=40,          fText=CHAR.icon.nextFrame},      -- 7
    WIDGET.newSlider{name='autoSkip',x=40, y=130,w=100,code=_setAS,   axis={0,2,1},     disp=function()return autoSkip end,show=_autoSkipDisp},
    WIDGET.newKey   {name='restart', x=0,  y=25, w=60, code=_restart, font=40,          fText=CHAR.icon.retry_spin},     -- 10
    WIDGET.newKey   {name='pause',   x=0,  y=25, w=60, code=pauseGame,font=40,          fText=CHAR.icon.pause},          -- 11
}

return scene
