--- activate under main muc component
--- Add the following config under the main muc component
---  muc_room_default_presence_broadcast = {
---        visitor = false;
---        participant = true;
---        moderator = true;
---    };
--- Enable in global modules: 's2s_bidi'
--- Make sure 's2s' is not in modules_disabled
local jid = require 'util.jid';
local st = require 'util.stanza';

local muc_domain_prefix = module:get_option_string('muc_mapper_domain_prefix', 'conference');
local main_domain = string.gsub(module.host, muc_domain_prefix..'.', '');

local function get_focus_occupant(room)
    local focus_occupant = room._data.focus_occupant;

    if focus_occupant then
        return focus_occupant;
    end

    for _, n_occupant in room:each_occupant() do
        if jid.node(n_occupant.jid) == 'focus' then
            room._data.focus_occupant = n_occupant;
            return n_occupant;
        end
    end

    return nil;
end

-- mark all occupants as visitors
module:hook('muc-occupant-pre-join', function (event)
    local occupant = event.occupant;

    if jid.host(occupant.bare_jid) == main_domain then
        occupant.role = 'visitor';
    end
end, 3);

-- when occupant is leaving forward presences to jicofo for visitors
-- do not check occupant.role as it maybe already reset
-- if there are no main occupants or no visitors, destroy the room (give 15 seconds of grace period for reconnections)
module:hook('muc-occupant-left', function (event)
    local room, occupant = event.room, event.occupant;
    local occupant_domain = jid.host(occupant.bare_jid);

    if occupant_domain == main_domain then
        local focus_occupant = get_focus_occupant(room);
        if not focus_occupant then
            module:log('warn', 'No focus found for %s', room.jid);
            return;
        end
        -- Let's forward unavailable presence to the special jicofo
        local pr = st.presence({ to = focus_occupant.jid, from = occupant.nick, type = 'unavailable' })
                     :tag('x', { xmlns = 'http://jabber.org/protocol/muc#user' })
                     :tag('item', {
            affiliation = room:get_affiliation(occupant.bare_jid) or 'none';
            role = 'none';
            nick = event.nick;
            jid = occupant.bare_jid }):up()
                :up();
        room:route_stanza(pr);
    end

    if not room.destroying then
        if room.xxl_destroy_timer then
            room.xxl_destroy_timer:stop();
        end

        room.xxl_destroy_timer = module:add_timer(15, function()
            -- let's check are all visitors in the room, if all a visitors - destroy it
            -- if all are main-participants also destroy it
            local main_count = 0;
            local visitors_count = 0;

            for _, o in room:each_occupant() do
                -- if there are visitor and main participant there is no point continue
                if main_count > 0 and visitors_count > 0 then
                    return;
                end

                if o.role == 'visitor' then
                    visitors_count = visitors_count + 1;
                else
                    main_count = main_count + 1;
                end
            end

            if main_count == 0 then
                module:log('info', 'Will destroy:%s main_occupants:%s visitors:%s', room.jid, main_count, visitors_count);
                room:destroy(nil, 'No main participants.');
            elseif visitors_count == 0 then
                module:log('info', 'Will destroy:%s main_occupants:%s visitors:%s', room.jid, main_count, visitors_count);
                room:destroy(nil, 'No visitors.');
            end
        end);
    end
end);

-- forward visitor presences to jicofo
module:hook('muc-broadcast-presence', function (event)
    local occupant = event.occupant;

    ---- we are interested only of visitors presence to send it to jicofo
    if occupant.role ~= 'visitor' then
        return;
    end

    local room = event.room;
    local focus_occupant = get_focus_occupant(room);

    if not focus_occupant then
        return;
    end

    local actor, base_presence, nick, reason, x = event.actor, event.stanza, event.nick, event.reason, event.x;
    local actor_nick;
    if actor then
        actor_nick = jid.resource(room:get_occupant_jid(actor));
    end

    -- create a presence to send it to jicofo, as jicofo is special :)
    local full_x = st.clone(x.full or x);

    room:build_item_list(occupant, full_x, false, nick, actor_nick, actor, reason);
    local full_p = st.clone(base_presence):add_child(full_x);
    full_p.attr.to = focus_occupant.jid;
    room:route_to_occupant(focus_occupant, full_p);
    return;
end);
