local sit = require 'room.sit'

function add_entity(handle, e)
    handle.properties.entities = handle.properties.entities or {}
    handle.properties.entities[e] = true
end

function save(handle)
    local ents = {}

    for e, _ in pairs(handle.properties.entities or {}) do
        local data = {}
        if e.properties.current_room then
            data.room = e.properties.current_room.room_id
            local script = require(e.properties.current_room.controller)
            data.room_data = script.save_idle(e.properties.current_room, e)
        end
        ents[e.id] = data
    end

    return {
        entities = ents,
    }
end

function load(handle, data)
    for e in pairs(handle.properties.entities or {}) do
        local data = data.entities[e.id]
        if data then
            if data.room then
                local room = handle:get_room_by_id(data.room)
                e.properties.current_room = room
                local users = room.properties.users or {}
                table.insert(users, e)
                room.properties.users = users

                local script = require(room.controller)
                script.load_idle(room, e, data.room_data)
            end
        end
    end
end

-- TODO: Use distance checks?
local function random_room(rooms)
    local offset = math.random(#rooms)
    for i = 1, #rooms do
        local room = rooms[((offset + i - 1) % #rooms) + 1]
        local users = room.properties.users or {}
        if room.properties.can_eat_at and #users < room.capacity then
            return room
        end
    end
    return nil
end

local function clear_entity(e)
    if e.properties.current_room and e.properties.current_room.valid then
        local room = e.properties.current_room
        local to_remove = -1
        for idx, ee in ipairs(room.properties.users) do
            if e == ee then
                to_remove = idx
                break
            end
        end
        if to_remove ~= -1 then
            table.remove(room.properties.users, to_remove)
        else
            print("Missing entity in room")
        end
    end
end

function update(handle)
    local rooms = handle.rooms
    local entities = handle.properties.entities or {}
    for e, _ in pairs(entities) do
        local data = {}
        if not e.valid then
            clear_entity(e)
            entities[e] = nil
        elseif (e.should_release and not e.properties.current_room)
            or (e.properties.current_room and not e.properties.current_room.valid)
        then
            clear_entity(e)
            entities[e] = nil
            e:release()
        elseif e.properties.release then
            clear_entity(e)
            e:set_var_int("last_eat", game_time())
            e:set_var_bool("has_eaten", true)
            if math.random() < 0.3 then
                e:set_var_int("trash_pickup_time", game_time())
                e:set_var_bool("has_trash", true)
            end
            entities[e] = nil
            e:release()
        elseif not e.properties.current_room or not e.properties.current_room.valid then
            local room = random_room(rooms)
            if room ~= nil then
                e.properties.current_room = room
                local users = room.properties.users or {}
                table.insert(users, e)
                room.properties.users = users
            else
                e.should_release = true
            end
        end
    end
end

local student_data = serialize.define({
    {"room", "i16"}
})
function update_client(handle, entities)
    for _, e in ipairs(entities) do
        if e.state ~= nil then
            local data = student_data.decode(e.state)
            local room = handle:get_room_by_id(data.room)
            local script = require(room.controller)
            script.client_idle(room, e)
        end
    end
end

function create_state(handle)
    return {}
end

function apply_state(handle, state)
end