local sit = require 'room.sit'

local student_data = serialize.define({
    {"sit", "bool"}
})

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

function save(handle)
    local ents = {}

    local rooms = {}
    for e, _ in pairs(handle.properties.entities or {}) do
        local data = {}
        if e.properties.room then
            data.room = e.properties.room.room_id
            rooms[e.properties.room] = true
            data.sit = sit.save_sitter(e.properties.room, e)
        end
        data.sit_time = e.properties.sit_time
        ents[e.id] = data
    end

    local rdata = {}
    for room, _ in pairs(rooms) do
        rdata[room.room_id] = {
            seats = sit.save_seats(room),
        }
    end

    return {
        entities = ents,
        rooms = rdata,
    }
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.room = room
                sit.load_sitter(room, e, data.sit)
            end
            e.properties.sit_time = data.sit_time
        end
    end
    for rid, data in pairs(data.rooms) do
        local room = handle:get_room_by_id(rid)
        sit.load_seats(room, data.seats)
    end
end

local function random_room(rooms)
    local offset = math.random(#rooms)
    for i = 1, #rooms do
        local room = rooms[((offset + i - 1) % #rooms) + 1]
        if room.properties.can_sit then
            return room
        end
    end
    return nil
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
            entities[e] = nil
        elseif e.should_release then
            sit.release_seat(e)
            if sit.try_stand(e, data) then
                entities[e] = nil
                e:release()
            else
                e.state = student_data.encode(data)
            end
        elseif not e.is_walking then
            if e.properties.room and e.properties.room.valid then
                local room = e.properties.room
                local rx, ry = room:get_position()
                local state = sit.try_find_and_sit(e, data, room.objects, {x=rx,y=ry})
                if state == sit.SITTING then
                    e.state = student_data.encode(data)
                    e:change_stat("happiness", 0.002 / 20.0)
                    e.properties.sit_time = (e.properties.sit_time or 0) - 1
                    if e.properties.sit_time <= 0 then
                        e.should_release = true
                    end
                elseif state == sit.NO_SEAT then
                    e.properties.room = nil
                    e.should_release = true
                end
            else
                e.properties.room = nil
                local room = random_room(rooms)
                if room ~= nil then
                    local rx, ry = room:get_position()
                    local state = sit.try_find_and_sit(e, data, room.objects, {x=rx,y=ry})
                    e.properties.sit_time = math.random(50, 200) * 20
                    if state == sit.SITTING then
                        e.state = student_data.encode(data)
                        e.properties.room = room
                    elseif state == sit.WALKING_TO_SEAT then
                        e.properties.room = room
                    else
                        e.should_release = true
                    end
                end
            end
        end
    end
end

function update_client(handle, entities)
    for _, e in ipairs(entities) do
        if e.state ~= nil then
            local data = student_data.decode(e.state)
            sit.client_sit_tick(e, data)
        end
    end
end

function create_state(handle)
    return {}
end

function apply_state(handle, state)
end