local sit = require 'room.sit'
local toilet_script = require 'room.toilet'

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
            data.stand_delay = e.properties['stand_delay']
            data.sit_time = e.properties['sit_time']
            data.stall = e.properties.current_room:object_index(e.properties['stall'])
        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

                e.properties.stand_delay = data.stand_delay
                e.properties.sit_time = data.sit_time
                if data.stall ~= nil then
                    e.properties['stall'] = room.objects[data.stall]
                end
            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.is_toilet and #users < room.capacity then
            return room
        end
    end
    return nil
end

local function clear_entity(e)
    if e.properties.current_room 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 then
            clear_entity(e)
            entities[e] = nil
            e:release()
        elseif e.properties.release then
            clear_entity(e)
            e:set_var_int("last_toilet", game_time())
            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

function update_client(handle, entities)
    for _, e in ipairs(entities) do
        if e.state ~= nil then
            local data = toilet_script.student_data.decode(e.state)
            local room = handle:get_room_by_id(data.room)
            toilet_script.client_idle(room, e)
        end
    end
end

function create_state(handle)
    return {}
end

function apply_state(handle, state)
end