local bump = require "bump"
local sti = require "sti"
local anim8 = require "anim8"


game_states = {}
--initial state GLOBAL
current_state = "title"

GLOBAL_COUNT = 1


function is_objective_item(other)
    --determines if other is an Objective Item
    if other.type == "resource" then
        return true
    end
    return false
end

function is_ritual_circle(other)
    --determines if other is an a ritual Circle 
    if other.type == "ritual" then
        return true
    end
    return false
end

function getTableLength(T)
    local count = 0
    for _ in pairs(T) do count = count + 1 end
    return count
end

function update_time(day, time)
    day.time = time
    if day.state == "day" and (day.time >= day.night_time) then
        
        local new_init = love.timer.getTime()
        day.init_time = new_init
        day_time = new_init
        day_state = "night"
        day.state = day_state
        daysound:stop()
        nightsound:play()
        --failurescreen()
    elseif day.state == "night" and (day.time >= day.death_time) then
        current_state = "game_over"
    end
end

function check_ritual_completed(player,day)
    --checks if the required ammount of items has been collected
    if getTableLength(player.inventory) >= player.objective_num then
        player.inventory = {}
        GLOBAL_COUNT = GLOBAL_COUNT + 1
        --day.count = day.count + 1
        current_state = "new_day"
        if day.state == "night" then
            nightsound:stop()
            daysound:play()
        end

    end

end

function point_in_rectangle(pointx, pointy, rectx, recty, rectwidth, rectheight)
    return pointx > rectx and pointy > recty and pointx < rectx + rectwidth and pointy < recty + rectheight
end

function take_objective_item(map, world, item, inventory)
    --want to remove item from map and put in inventory.
    local collidables = map.bump_collidables

    local objects = map.layers.Resources.resources


    
    for i=# collidables, 1, -1 do
        local obj = collidables[i]

        if obj.type then

            if obj.name == item.name then
               
                --remove from bump world
                world:remove(obj)
                table.remove(collidables, i)
                --remove from map
            end

        end
        

    end
    --remove from map 
    for i=# objects, 1, -1 do
        local obj = objects[i]

        if obj.id == item.id then
            table.remove(objects, i)
        end
    end
    --add item to inventory
    table.insert(inventory, item)
end

function init()

    first_init = love.timer.getTime()
    love.physics.setMeter(32)
    day_state = "day"


    Font = love.graphics.newFont("font.ttf", 50)

    -- Load a map exported to Lua from Tiled
    map = sti.new("map.lua", { "bump" })

    day = {
        count = GLOBAL_COUNT,
        time = first_init,
        night_time = 28,
        death_time = 7,
        init_time = first_init,
        state = day_state
    }

    
    
    local spawn
    local ritual
    local hut
    local resource_table = {}

    for k, object in pairs(map.objects) do
        local resource

        if object.name == "Player" then
            spawn = object
        elseif object.type == "ritual" then 
            ritual = object
        elseif object.type == "hut" then
            hut = object
        elseif object.type == "resource" then
            --resource_table
            local image = love.graphics.newImage("boulder.png")
            
            local resource = {
                image = image,
                id = object.id,
                name = object.name,
                r_type = object.type,
                x = object.x,
                y = object.y,
                w = image:getWidth(),
                h = image:getHeight()
            }
            resource_table[k] = resource

        end
    end

    map:addCustomLayer("RitualCircle", 4)
    local ritualLayer = map.layers["RitualCircle"]
    local image = love.graphics.newImage("ritual.png")
    ritualLayer.ritualcircle = {
        image = image, 
        --add some animations
        id = ritual.id,
        name = ritual.name,
        r_type = ritual.type,
        x = ritual.x,
        y = ritual.y,
        w = image:getWidth(),
        h = image:getHeight()
    }
    --add Hut 
    map:addCustomLayer("Hut", 5)
    local hutLayer = map.layers["Hut"]
    local image = love.graphics.newImage("hut.png")
    hutLayer.hut = {
        image = image, 
        --add some animations
        id = ritual.id,
        name = hut.name,
        r_type = hut.type,
        x = hut.x,
        y = hut.y,
        w = image:getWidth(),
        h = image:getHeight()
    }



    -- Create a Custom Layer
    map:addCustomLayer("Player Layer", 13)
    -- Add data to Custom Layer
    --local image = love.graphics.newImage("soldier.png")
    local image = love.graphics.newImage("player_new.png")

    local g64 = anim8.newGrid(64,64, 576,256, 6,6 , 0)


    local g32 = anim8.newGrid(24,32,image:getWidth(), image:getHeight() )

    local playerLayer = map.layers["Player Layer"]
        playerLayer.player = {
            image = image,
            downAnimation = anim8.newAnimation(g32('1-8',1), 0.1),
            upAnimation = anim8.newAnimation(g32('1-8',2), 0.1),
            leftAnimation = anim8.newAnimation(g32('1-8',3), 0.1),
            rightAnimation = anim8.newAnimation(g32('1-8',4), 0.1),
            --rightAnimation = anim8.newAnimation(gPlay('1-4',1), 0.1),
            direction = 0,
 
            inventory = {},
            objective_num = 1,
            x = spawn.x,
            y = spawn.y,
            w = 24,
            h = 32,
            r = 0,
            -- get offset value to center screen
            ox = 24 / 2,
            oy = 32 / 2
        }

    map:addCustomLayer("Resources",8)
    local resourceLayer = map.layers["Resources"]

    resourceLayer.resources = {}
    for _, resource in pairs(resource_table) do
        table.insert(resourceLayer.resources, resource)
    end

    world = bump.newWorld()
    --print(world)
    -- Prepare collision objects
    map:bump_init(world)
    local player = playerLayer.player
    --print(player.x)
    local offsetX = player.x - player.ox
    local offsetY = player.y - player.oy
    
    --world:add(player, player.x, player.y, player.w, player.h)
    world:add(player, player.x, player.y, 8, 16)
    table.insert(map.bump_collidables, player)

    function playerLayer:update(dt)
            local speed = 96
            local goalX = self.player.x
            local goalY = self.player.y

            if love.keyboard.isDown("w") or love.keyboard.isDown("up") then
                goalY = self.player.y - speed * dt
                self.player.upAnimation:update(dt)
                self.player.direction = 0
            end

            -- Move player down
            if love.keyboard.isDown("s") or love.keyboard.isDown("down") then
                goalY = self.player.y + speed * dt
                self.player.downAnimation:update(dt)
                self.player.direction = 1
            end

            -- Move player left
            if love.keyboard.isDown("a") or love.keyboard.isDown("left") then
                goalX = self.player.x - speed * dt
                self.player.leftAnimation:update(dt)
                self.player.direction = 2
            end

            -- Move player right
            if love.keyboard.isDown("d") or love.keyboard.isDown("right") then
                goalX = self.player.x + speed * dt
                self.player.rightAnimation:update(dt)
                self.player.direction = 3
            end

            local player_filter = function(item, other)
                if is_objective_item(other) then 
                    return 'cross'
                elseif is_ritual_circle(other) then 
                    return 'cross'
                end

                return 'slide'
            end

            local actualX, actualY, cols, len = world:move(self.player, goalX, goalY, player_filter)
            self.player.x = actualX
            self.player.y = actualY
            for i=1, len do
                local other = cols[i].other

                if (is_objective_item(other)) then
                    --print(other)
                    take_objective_item(map, world, other, self.player.inventory)
                elseif (is_ritual_circle(other)) then
                    check_ritual_completed(self.player,day)
                end
            end
    end

    -- Draw callback for Custom Layer
    function playerLayer:draw()
        --for _, sprite in pairs(self.sprites) do

        local x = math.floor(self.player.x)
        local y = math.floor(self.player.y)
        local r = self.player.r

        if self.player.direction == 0 then 
            self.player.upAnimation:draw(self.player.image, x, y, 0 ,1,1,self.player.ox, self.player.oy)
        end
        if self.player.direction == 1 then 
            self.player.downAnimation:draw(self.player.image, x, y, 0 ,1,1,self.player.ox, self.player.oy)
        end
        if self.player.direction == 2 then 
            self.player.leftAnimation:draw(self.player.image, x, y, 0 ,1,1,self.player.ox, self.player.oy)
        end
        if self.player.direction == 3 then 
            self.player.rightAnimation:draw(self.player.image, x, y, 0 ,1,1,self.player.ox, self.player.oy)
        end

        --end
    end
    function resourceLayer:draw()
        for _, resource in pairs(self.resources) do
            local x = math.floor(resource.x)
            local y = math.floor(resource.y)
            love.graphics.draw(resource.image,x,y)
        end
    end

    function ritualLayer:draw()
        local x = self.ritualcircle.x
        local y = self.ritualcircle.y
        love.graphics.draw(self.ritualcircle.image,x,y)
    end
    function hutLayer:draw()
        local x = self.hut.x
        local y = self.hut.y
        love.graphics.draw(self.hut.image,x,y)
    end
    map:removeLayer("Spawn Point")
    map:removeLayer("objective")
    map:removeLayer("ritual circle")
    map:removeLayer("hut spawn")
end
function love.load()
    daysound = love.audio.newSource("daytime.wav", "static")
    nightsound = love.audio.newSource("night_time.wav", "static")
    daysound:setLooping(true)
    nightsound:setLooping(true)
    default_font = love.graphics.getFont()
    title_image = love.graphics.newImage("title.png")
    game_over_image = love.graphics.newImage("gameover.png")
    new_day_image = love.graphics.newImage("new_day.png")
    init()
end


function love.update(dt)
    if current_state == "title" then
        --do title stuff
        --check if mouse is hovering over button
        daysound:play()
        local cursorX = love.mouse.getX()
        local cursorY = love.mouse.getY()

        local start_game = point_in_rectangle(cursorX, cursorY, 480, 250, 270, 90)
        if start_game and love.mouse.isDown(1) then 
            init()
            current_state = "game"
        end

        --title:update(dt)

    
    elseif current_state == "game" then
        local initTime = day.init_time
        local currentTime = love.timer.getTime()
        local timeDelta = math.floor(currentTime - initTime)
        update_time(day, timeDelta)
        --update_day()
        map:update(dt)

    elseif current_state == "new_day" then
        --GLOBAL_COUNT = GLOBAL_COUNT + 1
        local cursorX = love.mouse.getX()
        local cursorY = love.mouse.getY()
        local next_day = point_in_rectangle(cursorX, cursorY, 270, 280, 270, 90)
        if next_day and love.mouse.isDown(1) then 
            init()
            current_state = "game"
        end

    elseif current_state == "game_over" then
        GLOBAL_COUNT = 1
        local cursorX = love.mouse.getX()
        local cursorY = love.mouse.getY()
        local main_menu = point_in_rectangle(cursorX, cursorY, 270, 180, 270, 90)
        local exit_game = point_in_rectangle(cursorX, cursorY, 270, 280, 270, 90)
        if main_menu and love.mouse.isDown(1) then 
            current_state = "title"
            nightsound:stop()
        elseif exit_game and love.mouse.isDown(1) then 
            love.event.quit()
        end
        --
    end

end

function love.draw()
    -- Translation would normally be based on a player's x/y
    if current_state == "title" then

        love.graphics.draw(title_image, 0,0)
        love.graphics.setColor(0,0,0,0)
        love.graphics.rectangle("fill", 480, 250, 270, 90)
        love.graphics.setColor(255,255,255)
        
        pressed = false
    elseif current_state == "new_day" then
        love.graphics.draw(new_day_image, 0,0)
        love.graphics.setFont(Font)
        love.graphics.setColor(0,0,0)
        love.graphics.print(GLOBAL_COUNT,450,150)
        love.graphics.setColor(255,255,255)
        love.graphics.setFont(default_font)
    
    elseif current_state == "game" then
        local scale = 2

        local screen_width = love.graphics.getWidth() / scale
        local screen_height = love.graphics.getHeight() / scale
        local player = map.layers["Player Layer"].player
       
     
        local translateX = math.floor(player.x - screen_width / 2)
        local translateY = math.floor(player.y - screen_height / 2)
     
        love.graphics.scale(scale)
        love.graphics.translate(-translateX, -translateY)

        map:draw()

        if day_state == "day" then 
            local decreaseTime = day.time * 15 
            love.graphics.rectangle("fill", (player.x -210), (player.y - 160), (410 - decreaseTime), 25)
            love.graphics.setColor(0,0,0)
            love.graphics.print("day time left!", (player.x -200), (player.y - 150))
        elseif day_state == "night" then
            local decreaseTime = day.time * 60
            love.graphics.setColor(0,0,0)
            love.graphics.rectangle("fill", (player.x -210), (player.y - 160), (410 - decreaseTime), 25)
            love.graphics.setColor(255,255,255)
            love.graphics.print("night time left!", (player.x -200), (player.y - 150))
            love.graphics.setColor(20,41,119,150)
            love.graphics.rectangle("fill", 0,0, 1000, 1000)
            love.graphics.setColor(255,255,255)

        end

        love.graphics.setColor(255,255,255,100)
        love.graphics.rectangle("fill", (player.x -50), (player.y + 130), 150, 30)
        love.graphics.setColor(0,0,0)
        love.graphics.print("Resources gathered " ..getTableLength(player.inventory), (player.x -50), (player.y + 130))
        -- Draw Collision Map (useful for debugging)
        love.graphics.setColor(255, 0, 0, 255)
        --map:bump_draw(world)

        -- Reset color
        love.graphics.setColor(255, 255, 255, 255)
    elseif current_state == "game_over" then
        love.graphics.draw(game_over_image, 0, 0)
        
    end
end