local Global = require 'utils.global'
local Event = require 'utils.event'

local this = {
    fullness_enabled = true,
    warned = {}
}

Global.register(
    this,
    function (t)
        this = t
    end
)

local Public = {}
local random = math.random
local ceil = math.ceil
local floor = math.floor

local function is_player_warned(player, reset)
    if reset and this.warned[player.index] then
        this.warned[player.index] = nil
        return
    end
    if not this.warned[player.index] then
        this.warned[player.index] = {
            count = 2
        }
    end
    this.warned[player.index].count = this.warned[player.index].count + 1
    return this.warned[player.index]
end

local function compute_fullness(player, position)
    if not player.mining_state.mining then
        return false
    end

    if player.controller_type == defines.controllers.remote then
        return
    end

    local warn_player = is_player_warned(player)
    local free_slots = player.get_main_inventory().count_empty_stacks()
    local inventory_size = #player.get_main_inventory()
    if free_slots == 0 or free_slots == 1 then
        if player.character and player.character.valid then
            local damage = ceil((warn_player.count / 2) * warn_player.count)
            if player.character.health >= damage then
                player.character.damage(damage, 'player', 'explosion')
                player.character.surface.create_entity({ name = 'water-splash', position = player.position })
                local messages = {
                    'Ouch.. That hurt! Better be careful now.',
                    'Just a fleshwound.',
                    'Better keep those hands to yourself or you might loose them.'
                }
                player.create_local_flying_text(
                    {
                        position = { position.x, position.y + 0.6 },
                        text = messages[random(1, #messages)],
                        color = { r = 0.75, g = 0.0, b = 0.0 }
                    }
                )
            else
                player.character.die('enemy')
                is_player_warned(player, true)
                game.print(player.name .. ' should have emptied their pockets.', { r = 0.75, g = 0.0, b = 0.0 })
                return free_slots
            end
        end
    else
        is_player_warned(player, true)
    end
    if free_slots > 1 then
        if floor(inventory_size / free_slots) == 10 then -- When player has 10% free slots
            player.create_local_flying_text(
                {
                    position = { position.x, position.y + 0.6 },
                    text = 'You are feeling heavy',
                    color = { r = 1.0, g = 0.5, b = 0.0 }
                }
            )
        end
    end
    return free_slots
end

function Public.check_fullness(player, position)
    if this.fullness_enabled then
        local fullness = compute_fullness(player, position)
        if fullness == 0 then
            return
        end
    end
end

function Public.enable_fullness(value)
    if value then
        this.fullness_enabled = value
    else
        this.fullness_enabled = false
    end
    return this.fullness_enabled
end

function Public.get(key)
    if key then
        return this[key]
    else
        return this
    end
end

local check_fullness = Public.check_fullness

Event.add(
    defines.events.on_player_mined_entity,
    function (event)
        local entity = event.entity
        if not entity or not entity.valid then
            return
        end

        local player = game.players[event.player_index]
        if not player or not player.valid then
            return
        end

        if entity.name == 'entity-ghost' then
            return
        end

        if not this.fullness_enabled then
            return
        end

        local position = event.entity.position
        check_fullness(player, position)
    end
)

return Public
