local gc,kb,tc=love.graphics,love.keyboard,love.touch
local rnd,floor,abs=math.random,math.floor,math.abs
local max,min=math.max,math.min
local setFont,mStr=FONT.set,GC.mStr

local cubeColor={
    {.88,.75,.00},
    {.50,.50,.97},
    {.50,.50,.50},
    {.50,.97,.00},
    {.94,.94,.94},
    {.40,.40,.40},
    {.31,.88,.97},
    {.97,.97,.50},
    {.91,.50,.97},
    {.97,.63,.31},
    {0,0,0},
}

local cubesX,cubesY
local lastCube
local player,moveDir
local life,life1,inv
local level,speed
local menu,ct,play
local score
local sunH,color,rot

local function near(o,t)
    return o>t and max(o-.01,t) or o<t and min(o+.01,t) or o
end
local function hurt(i)
    life=life-i
    if life<0 then
        life=-100
        menu,play=1,false
        speed=speed*.5
        moveDir=0
        score=floor(score)
        SFX.play('clear_4')
    else
        SFX.play('clear_2')
    end
end

local scene={}

function scene.enter()
    cubesX={} for i=1,40 do cubesX[i]=rnd()*16-8 end
    cubesY={} for i=1,40 do cubesY[i]=i/40*9 end
    lastCube=1
    player,moveDir=0,0
    life,life1,inv=0,0,false
    level,speed=1,1
    menu,ct,play=false,60,false
    score=0
    sunH,color,rot=0,{.878,.752,0},0

    gc.setLineJoin('bevel')
    BGM.play('push')
    BG.set('none')
    DiscordRPC.update("Playing Cubefield")
end

function scene.touchDown(x)
    if play then
        if x<640 then
            moveDir=-1
        else
            moveDir=1
        end
    end
end
function scene.touchUp(x)
    if play then
        local L=tc.getTouches()
        if x<640 then
            for i=1,#L do
                if tc.getPosition(L[i])>640 then
                    moveDir=1
                    return
                end
            end
        else
            for i=1,#L do
                if tc.getPosition(L[i])<640 then
                    moveDir=-1
                    return
                end
            end
        end
        moveDir=0
    else
        scene.keyDown('space')
    end
end
function scene.keyDown(key,isRep)
    if isRep then return end
    if key=='escape' then
        SCN.back()
    elseif play then
        if key=='left' or key=='a' then
            moveDir=-1
        elseif key=='right' or key=='d' then
            moveDir=1
        end
    else
        if key=='space' and ct==60 then
            menu=-1
            speed=1
            level=1
        end
    end
end
function scene.keyUp(key)
    if play then
        if key=='left' or key=='a' then
            moveDir=kb.isDown('right','d') and 1 or 0
        elseif key=='right' or key=='d' then
            moveDir=kb.isDown('left','a') and -1 or 0
        end
    end
end

function scene.update(dt)
    if dt>.06 then dt=.06 end
    dt=dt*600

    -- Update cubes' position
    local cy=cubesY
    local step=speed*dt*.005
    for i=1,40 do
        cy[i]=cy[i]+step
        if cy[i]>10 then
            if score%1000<820 then
                cubesX[i]=rnd()*16-8+player
            else
                cubesX[i]=player+i%2*6-3
            end
            cy[i]=cy[i]-9
            lastCube=(lastCube-2)%40+1
        end
    end

    -- Collision detect
    if play then
        for j=1,40 do
            local i=(j+lastCube-2)%40+1
            local Y=cubesY[i]
            if Y<8.8 then
                local size=100/(10-Y)
                local x=(cubesX[i]-player)/(10-Y)*200-size*.5
                local y=5/(10-Y)*150-50
                if y>420 and y<480 and x<8 and x+size>-8 and inv==0 then
                    cubesX[i]=cubesX[i]-3
                    hurt(650)
                    inv=40
                end
            end
        end
    end

    -- Screen rotation
    if moveDir~=0 then
        player=player+moveDir*dt*.003*speed^.8
        if abs(rot)<.16 or moveDir*rot>0 then
            rot=rot-moveDir*dt*.0003*speed
        end
    elseif rot~=0 then
        local d=dt*.0002*speed
        if rot>0 then
            rot=max(rot-d,0)
        else
            rot=min(rot+d,0)
        end
    end

    life1=MATH.expApproach(life1,life,dt*16)

    if play then
        if inv>0 then
            inv=inv-1
        end
        score=score+dt*.04+life*.0004
        life=min(life+dt*.04,1000)
        if score>1000*level then
            if speed<3 then
                speed=speed+.2
            end
            level=level+1
            SFX.play('warn_1')
        end
        sunH=sunH+.01
    elseif menu==1 then
        ct=ct+1
        if ct==60 then
            menu=false
        end
    elseif menu==-1 then
        for i=1,3 do color[i]=near(color[i],cubeColor[1][i]) end
        for i=1,40 do cubesY[i]=cubesY[i]-(70-ct)*.003 end
        if sunH>0 then
            sunH=max(sunH*.85-1,0)
        end
        ct=ct-1
        if ct==0 then
            local t=CLIPBOARD.get()
            if type(t)=='string' then
                t=t:lower():match("^s=(%d+)$")
                t=t and tonumber(t) and tonumber(t)>0 and tonumber(t)<=8000 and floor(tonumber(t))
            end
            score=type(t)=='number' and t or 0
            life=1000
            play,menu=true,false
            inv=90
        end
    end
end

local function _sunStencil()
    gc.rectangle('fill',-60,-440,120,120)
end
function scene.draw()
    -- Health bar
    if life1>0 then
        gc.setColor(1,0,0)
        gc.rectangle('fill',640-life1*.64,710,life1*1.28,10)
    end

    -- Draw player
    if play and inv%8<4 then
        gc.setColor(COLOR.Z)
        gc.rectangle('fill',620,670,40,40)
    end

    -- Set screen rotation
    gc.push('transform')
    gc.translate(640,690)
    gc.rotate(rot)

    -- Draw sun
    gc.setStencilTest('notequal',1)
    gc.stencil(_sunStencil)
    gc.setColor(.7,.5,.3)
    gc.circle('fill',0,-380-sunH,60)
    gc.setStencilTest()

    -- Draw direction
    if play then
        gc.setLineWidth(3)
        gc.setColor(1,1,1,.1)
        gc.polygon('fill',-15,30,0,-440,15,30)
    end

    -- Draw Horizon/Direction
    gc.setColor(COLOR.Z)
    gc.line(-942,-440,942,-440)

    -- Draw cubes
    for j=1,40 do
        local i=(j+lastCube-2)%40+1
        local Y=cubesY[i]
        if Y<8.8 then
            local size=100/(10-Y)
            local x=(cubesX[i]-player)/(10-Y)*200-size*.5
            local y=5/(10-Y)*150-50
            if Y>1 then
                gc.setColor(color)
                gc.rectangle('fill',x,y-485,size,size)
                gc.setLineWidth(size*.05)
                gc.setColor(COLOR.Z)
                gc.rectangle('line',x,y-485,size,size)
            end
        end
    end

    -- Draw menu
    if play then
        setFont(60)
        mStr(floor(score),-300,-640)
        mStr(floor(score),300,-640)
        if score%1000>920 then
            gc.setColor(1,1,1,abs(score%1000-970)*8)
            setFont(70)
            if level<11 then
                mStr("++SPEED++",0,-650)
                for i=1,3 do
                    color[i]=near(color[i],cubeColor[level+1][i])
                end
            else
                mStr("!!MAXSPEED!!",0,-650)
            end
        end
    else
        gc.setColor(COLOR.Z)
        gc.rectangle('fill',-20,-20+ct,40,40)

        gc.setColor(1,1,1,(1-ct/60)*.1)
        gc.polygon('fill',-15,30,0,-440,15,30)

        gc.setColor(1,1,1,ct/60)

        setFont(90)
        mStr("CubeField",0,-650)

        setFont(20)
        gc.print("Original game by Max Abernethy",40,-550)
        gc.print("Original CX-CAS version by Loïc Pujet",40,-525)
        gc.print("Ported / Rewritten / Balanced by MrZ",40,-500)

        setFont(45)
        if score>0 then
            mStr("Score : "..score,0,-350)
        end

        mStr(MOBILE and "Touch to Start" or "Press space to Start",0,-160)
    end
    gc.pop()
end

scene.widgetList={
    WIDGET.newKey{name='back',x=1140,y=80,w=170,h=80,sound='back',font=60,fText=CHAR.icon.back,code=backScene},
}

return scene
