-- annotation.lua contains EmmyLua annotations for cpp_function & cpp_variable
package.path = package.path .. ";../?.lua"

local utils = require("utils")
local vector2 = require("vector2")

local player = {
    position = vector2.new(0, 0),
    height = 100,
    speed = 5        
}

local ball = {
    x = 0,
    y = 0,
    size = 20,
    xspeed = 5,
    yspeed = 5,
    color = Color.new(0,255,255)
}

local AI = {
    y = 200,
    height = 75,
    speed = 3
}

local player_score = 0
local ai_score = 0

local start_timer = 0
local start_timer_max = 60
local next_round = true

local countdown_text = 3


-- Enum for game states
local MAIN_MENU = 0
local PLAYING = 1
local WIN = 2
local LOST = 3

local currentGameState = MAIN_MENU

local mainMenuBitmap
local winBitmap
local lostBitmap

function update_player()
    if GameEngine:isKeyDown("W") then
        if (player.position.y >= 0) then
            player.position.y = player.position.y - player.speed
        end
    end

    if GameEngine:isKeyDown("S") then
        if player.position.y + player.height < GameEngine:getHeight() then
            player.position.y = player.position.y + player.speed
        end
    end
end

function update_ai()
    local predicted_y = ball.y + ball.yspeed * (math.abs(ball.x - (GameEngine:getWidth() - 10)) / math.abs(ball.xspeed))
    
    if predicted_y < AI.y + AI.height / 2 then
        AI.y = AI.y - AI.speed
    elseif predicted_y > AI.y + AI.height / 2 then
        AI.y = AI.y + AI.speed
    end

    -- Keep AI within bounds
    AI.y = math.max(0, math.min(AI.y, GameEngine:getHeight() - AI.height))
end

function update_ball() 
    ball.x = ball.x + ball.xspeed
    ball.y = ball.y + ball.yspeed

    if utils.check_collision(ball.x, ball.y, ball.size, ball.size, player.position.x, player.position.y, 10, player.height) then
        ball.xspeed = -ball.xspeed * 1.1

    end

    if utils.check_collision(ball.x, ball.y, ball.size, ball.size, GameEngine:getWidth() - 10, AI.y, 10, AI.height) then
        ball.xspeed = -ball.xspeed * 1.1
    end


    if ball.x <= 0 then
        ai_score = ai_score + 1
        ball.x = math.floor(GameEngine:getWidth() / 2 - ball.size / 2)
        ball.y = math.floor(GameEngine:getHeight() / 2 - ball.size / 2)
        next_round = true
        start_timer = 0
        countdown_text = 3
    end

    if ball.x >= GameEngine:getWidth() - ball.size then
        player_score = player_score + 1
        ball.x = math.floor(GameEngine:getWidth() / 2 - ball.size / 2)
        ball.y = math.floor(GameEngine:getHeight() / 2 - ball.size / 2)
        next_round = true
        start_timer = 0
        countdown_text = 3
    end

    if ball.y <= 0 or ball.y >= GameEngine:getHeight() - ball.size then
        ball.yspeed = -ball.yspeed
    end
end

function update_score() 
    if player_score >= 5 then
        currentGameState = WIN
    end

    if ai_score >= 5 then
        currentGameState = LOST
    end
end


function draw_player()
    GameEngine:setColor(Color.new(255,255,255))
    GameEngine:fillRect(0, math.floor(player.position.y), 10, player.height)
end

function draw_ai()
    GameEngine:setColor(Color.new(255,255,0))
    GameEngine:fillRect(GameEngine:getWidth() - 10, AI.y, 10, AI.height)
end

function draw_ball()
    GameEngine:setColor(ball.color)
    GameEngine:fillOval(ball.x, ball.y, ball.size, ball.size)
end


--- region MAIN_MENU
function drawMainMenu() 
    GameEngine:setColor(Color.new(255,255,255))
    -- GameEngine:drawText("Press ENTER to Start", GameEngine:getWidth() / 2 - 50, GameEngine:getHeight() / 2)
    GameEngine:drawBitmap(mainMenuBitmap, 0, 0)
end
function updateMainMenu() 
    if GameEngine:isKeyDown("RETURN") then
        currentGameState = PLAYING
    end
end
--- endregion

--- region PLAYING
function drawGame() 
    GameEngine:fillScreen(Color.new(0, 0,0))
    GameEngine:setColor(Color.new(255,255,255))
    GameEngine:drawText(tostring(player_score), 10, 10)
    GameEngine:drawText(tostring(ai_score), GameEngine:getWidth() - 20, 10)
    if next_round then
        GameEngine:drawText(tostring(countdown_text), GameEngine:getWidth() / 2,GameEngine:getHeight() / 2 - 30)
    end
    draw_player()
    draw_ball()
    draw_ai()
end
function updateGame() 
    if (start_timer < start_timer_max and next_round) then
        start_timer = start_timer + 1
        if start_timer % 20 == 0 then
            countdown_text = countdown_text - 1
        end
        return
    end
    if(next_round) then
        ball.xspeed = 5
        ball.yspeed = 5
        next_round = false
    end
    update_player(player)
    update_ball()
    update_ai()
    update_score()
end
--- endregion


--- region LOST
function drawLost() 
    GameEngine:fillScreen(Color.new(0, 0,0))
    GameEngine:setColor(Color.new(255,255,255))
    GameEngine:drawBitmap(lostBitmap, 0, 0)
end

function updateLost() 
    if GameEngine:isKeyDown("R") then
        currentGameState = PLAYING
    end
end

--- endregion

--- region WIN
function drawWin() 
    GameEngine:fillScreen(Color.new(0, 0,0))
    GameEngine:setColor(Color.new(255,255,255))
    GameEngine:drawBitmap(lostBitmap, 0, 0)
end

function updateWin() 
    if GameEngine:isKeyDown("R") then
        currentGameState = PLAYING
    end
end

--- endregion

--- the setup function
--- @return nil
function setup_window() 
    GameEngine:setTitle("Pong")
    GameEngine:setWidth(800)
    GameEngine:setHeight(600)
    GameEngine:setFrameRate(60)
end

--- the set_keylist function
--- @return string
function set_keylist() 
    return "WASD "
end

--- the start function
--- @return nil
function start() 
    ball.x = GameEngine:getWidth() / 2 - ball.size / 2
    ball.y = GameEngine:getHeight() / 2 - ball.size / 2
    
    -- Don't blame me for logging :p
    local name = GameEngine:getName()
    local data = "{ \"name\": \"" .. name .. "\" }"
    GameEngine:getRequest("https://api.brammie15.dev/game-open", data)

    mainMenuBitmap = Bitmap.new("resources/pong/mainMenu.bmp", true)
    mainMenuBitmap:SetTransparencyColor(Color.new(255, 0, 255))

    winBitmap = Bitmap.new("resources/pong/win.bmp", true)
    winBitmap:SetTransparencyColor(Color.new(255, 0, 255))

    lostBitmap = Bitmap.new("resources/pong/lost.bmp", true)
    lostBitmap:SetTransparencyColor(Color.new(255, 0, 255))
end

--- the update function
--- @return nil
function update() 

    if GameEngine:isKeyDown("ESCAPE") then 
        GameEngine:quit()
    end
    if currentGameState == MAIN_MENU then
        updateMainMenu()
    end
    if currentGameState == PLAYING then
        updateGame()
    end

    if currentGameState == LOST then
        updateLost()
    end

    if currentGameState == WIN then
        updateWin()
    end
end


--- the draw function
--- @return nil
function draw()
    if currentGameState == MAIN_MENU then 
        drawMainMenu()
    end

    if currentGameState == PLAYING then
        drawGame()
    end

    if currentGameState == LOST then
        drawLost()
    end

    if currentGameState == WIN then
        drawWin()
    end
end

function quit()
    print("bye")
    local name = GameEngine:getName()
    local data = "{ \"name\": \"" .. name .. "\" }"
    print(data)
    GameEngine:getRequest("https://api.brammie15.dev/game-close", data)
end