{{JS_PREFIX}}_supports_keywords = true;
{{JS_PREFIX}}_idle_interval = 4000;

const log = {{PAGE_PREFIX}}_log;

function {{JS_PREFIX}}_getElementsByXPath(xpath, parent) {
    let results = [];
    let query = document.evaluate(xpath, parent || document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (let i = 0, length = query.snapshotLength; i < length; ++i) {
        results.push(query.snapshotItem(i));
    }
    return results;
}

const {{JS_PREFIX}}_site_host = location.protocol + '//' + window.location.hostname + '/';
const {{JS_PREFIX}}_mobile = window.location.hostname === "m.facebook.com";

const {{JS_PREFIX}}_jail = document.createElement('div');
{{JS_PREFIX}}_jail.style.display = 'none';

const {{JS_PREFIX}}_site_onload = function () {
    document.getElementsByTagName('body')[0].appendChild({{JS_PREFIX}}_jail);
}

const {{JS_PREFIX}}_appendChild = Element.prototype.appendChild;
Element.prototype.appendChild = function() {
    const node = arguments[0];
    try {
        if (node.tagName) {
            if ( ({{JS_PREFIX}}_mobile && node.tagName.toUpperCase() === 'ARTICLE')
                || (!{{JS_PREFIX}}_mobile && node.tagName.toUpperCase() === 'DIV' && node.getAttribute('role') && node.getAttribute('role') === 'article') ) {
                const block = {{JS_PREFIX}}_should_block({{JS_PREFIX}}_blocked_users, node)
                if (block) {
                    // log('>>> BLOCKING via appendChild: '+block);
                    return {{JS_PREFIX}}_appendChild.apply({{JS_PREFIX}}_jail, arguments);
                }
            }
        }
    } catch (e) {
        console.log('>>> error inspecting: e='+e);
    }
    try {
        return {{JS_PREFIX}}_appendChild.apply(this, arguments);
    } catch (e) {
        console.log('>>> error calling document.appendChild: arg[0].tagName = '+node.tagName+' e='+e);
    }
};

function {{JS_PREFIX}}_remove_item_from_dom(item, authorName) {
    try {
        const feedItem = {{JS_PREFIX}}_find_feed_item(item);
        // console.log('remove_item_from_dom: removing: '+item.outerHTML);
        if (feedItem.parentElement) {
            feedItem.innerHTML = '';
        }
    } catch (e) {
        log('error removing post by author: ' + authorName + ': ' + e);
    }
}

function {{JS_PREFIX}}_is_ad(article) {
    return typeof Array.from(article.getElementsByTagName('a')).find(a => a.href && a.href.indexOf('/ads/about') !== -1) !== 'undefined';
}

function {{JS_PREFIX}}_author_display_name(link) {
    let strongs = Array.from(link.getElementsByTagName('strong'));
    if (strongs.length === 0) return 'null (no <strong> element found)';
    let spans = Array.from(strongs[0].getElementsByTagName('span'));
    if (spans.length === 0) return 'null (no <span> element found within <strong>)';
    return spans[spans.length-1];
}

function {{JS_PREFIX}}_find_feed_item(article) {
    return {{JS_PREFIX}}_mobile
        ? article
        : article.parentElement.parentElement.parentElement.parentElement.parentElement;  // todo: safer to walk upwards until we find FeedItem
}

function {{JS_PREFIX}}_remove_item(item, authorName) {
    if (item.className.indexOf('{{JS_PREFIX}}_bub_blocked') === -1) {
        // log('removing post by author: ' + authorName);
        item.className = item.className + ' {{JS_PREFIX}}_bub_blocked';
        {{JS_PREFIX}}_remove_item_from_dom(item, authorName);
    } else {
        console.log('found post marked removed but still present (??) by author: ' + authorName);
    }
}

function {{JS_PREFIX}}_create_block_control(item, authorLink, authorName, size) {
    let linkClass = authorLink.className;
    if (linkClass && linkClass.indexOf('{{JS_PREFIX}}_link_decorated') !== -1) {
        return null;
    } else {
        authorLink.className = authorLink.className ? authorLink.className + ' {{JS_PREFIX}}_link_decorated' : '{{JS_PREFIX}}_link_decorated';
    }
    const imgHolder = {{JS_PREFIX}}_create_block_img(size);
    const blockSpan = document.createElement('span');
    const blockLink = document.createElement('a');
    blockLink.style.zIndex = '{{APP_CONTROLS_Z_INDEX}}'
    blockLink.style.cursor = 'pointer';
    blockLink.addEventListener("click", function (e) {
        {{JS_PREFIX}}_remove_item_from_dom(item, authorName);
        {{JS_PREFIX}}_block_user(authorName);
        e.stopPropagation();
        e.preventDefault();
        return false;
    });
    blockLink.appendChild(imgHolder);
    blockSpan.appendChild(document.createTextNode('\u00A0\u00A0'));
    blockSpan.appendChild(blockLink);
    blockSpan.id = 'blockSpan_'+{{JS_PREFIX}}_uuidv4();
    // console.log('adding block control on '+authorName);
    return blockSpan;
}

function {{JS_PREFIX}}_is_author_link(href) {
    if (href.length === 0) return false;
    const non_authors = ['friends', 'photo', 'memories', 'photo.php', 'story.php', 'a', 'a/comment.php', 'comment'];
    let h = href.startsWith({{JS_PREFIX}}_site_host) ? href.substring({{JS_PREFIX}}_site_host.length) : href;
    const qPos = h.indexOf('?');
    if (qPos !== -1) {
        h = h.substring(0, qPos);
    }
    if (h.endsWith('/')) h = h.substring(0, h.length - 1);
    if (non_authors.indexOf(h) !== -1) return false;
    const matches = h.match(/\//g);
    if (matches !== null) {
        // log('>>>>>> not a top-level link: h='+h+', href='+href);
    } else {
        // console.log('href is toplevel: '+href+', matches='+matches);
    }
    return matches === null;
}

function {{JS_PREFIX}}_clean_author_link(authorLink) {
    const sitePrefix = {{JS_PREFIX}}_site_host;
    let authorHref = authorLink.href;
    let authorName = authorHref.startsWith(sitePrefix) ? authorHref.substring(sitePrefix.length) : authorHref;
    const qPos = authorName.indexOf('?');
    if (authorName.startsWith('profile.php?')) {
        const andPos = authorName.indexOf('&');
        if (andPos !== -1) {
            authorName = authorName.substring(0, andPos);
            authorLink.href = sitePrefix + authorName;
        }
    } else {
        if (qPos !== -1) {
            authorName = authorName.substring(0, qPos);
            authorLink.href = sitePrefix + authorName;
        }
        if (authorName.endsWith('/')) authorName = authorName.substring(0, authorName.length - 1);
    }
    return authorName;
}

function {{JS_PREFIX}}_block_or_decorate(firstEval, item, authorLink, authorName, authorDisplay, blocked_users, size) {
    if (authorName in blocked_users) {
        // console.log('found blocked user: '+authorName);
        {{JS_PREFIX}}_tally_author_block(authorName == null ? {{PAGE_PREFIX}}_msg_or_default({{JS_PREFIX}}_messages, 'web_advertOrOtherBlock', 'ad/other') : authorName);
        if (!firstEval) {{JS_PREFIX}}_untally_allow();
        return {author: authorName == null ? true : authorName, item: item};
    } else {
        try {
            let b = {{JS_PREFIX}}_create_block_control(item, authorLink, authorName, size);
            // console.log('inserting span='+b.id+' for item by '+authorName);
            if (b !== null) authorDisplay.parentNode.appendChild(b);

        } catch (e) {
            log('badness: '+e);
        }
    }
    return null;
}

function {{JS_PREFIX}}_should_block_comment(blocked_users, comment) {

    const mobile = {{JS_PREFIX}}_mobile;
    const firstEval = {{JS_PREFIX}}_mark_evaluated(comment);

    const authorLinks = Array.from(comment.getElementsByTagName('a'));
    for (let i=0; i<authorLinks.length; i++) {
        const authorLink = authorLinks[i];
        if (!{{JS_PREFIX}}_is_author_link(authorLink.href)) continue;

        const authorName = {{JS_PREFIX}}_clean_author_link(authorLink);
        if (Array.from(authorLink.getElementsByTagName('i')).filter(i => i.className.indexOf('profpic') !== -1).length > 0) {
            // do not consider profile pic link
            continue;
        }
        const authorDisplay = mobile
            ? authorLink
            : authorLink.getElementsByTagName('span')[0]; // todo: is this right?
        // walk upwards until we find the comment or comment-reply, there could be something nested
        let node = authorLink.parentElement;
        let foundComment = null;
        for (let i=0; i<10; i++) {
            if (node === comment || {{JS_PREFIX}}_div_is_comment_reply(node)) {
                foundComment = node;
                break;
            }
            node = node.parentElement;
        }
        if (foundComment === null) {
            console.log('no parent comment found for authorLink: '+authorLink.outerHTML);
            continue;
        }
        if ({{JS_PREFIX}}_includes_block_keyword(foundComment, firstEval)) {
            // log('should_block returning true for keyword block');
            return foundComment;
        }
        const blocked = {{JS_PREFIX}}_block_or_decorate(firstEval, foundComment, authorLink, authorName, authorDisplay, blocked_users, 16);
        if (firstEval) {
            // console.log('>>> allowing post with firstAuthor = '+firstAuthor);
            {{JS_PREFIX}}_tally_allow();
        }
        if (blocked) return blocked;
    }
    return null;
}

function {{JS_PREFIX}}_should_block(blocked_users, article) {
    const mobile = {{JS_PREFIX}}_mobile;
    const log = {{PAGE_PREFIX}}_log;

    const firstEval = {{JS_PREFIX}}_mark_evaluated(article);

    if ({{JS_PREFIX}}_includes_block_keyword(article, firstEval)) {
        // log('should_block returning true for keyword block');
        return {item: article, author: null};
    }

    const authorLinks = Array.from(article.getElementsByTagName('a'))
        .filter(a => {{JS_PREFIX}}_is_author_link(a.href))
        .filter(a => a.getElementsByTagName('svg').length === 0)
        .filter(a => mobile ? a.parentElement.tagName.toUpperCase() === 'STRONG' : true);

    let firstAuthor = null;
    for (let authIndex=0; authIndex<authorLinks.length; authIndex++) {
        const authorLink = authorLinks[authIndex];
        const authorName = {{JS_PREFIX}}_clean_author_link(authorLink);
        if (firstAuthor === null) firstAuthor = authorName;

        const authorDisplay = mobile
            ? authorLink
            : authorLink.getElementsByTagName('span')[0];
        const authorDisplayName = authorDisplay.innerHTML;

        // walk up until we find the article or comment
        let node = authorLink.parentElement;
        let foundItem = null;
        for (let i=0; i<20; i++) {
            if (node === article) {
                foundItem = node;
                break;
            } else if (node.tagName.toUpperCase() === 'DIV'
                && ( (!mobile && node.getAttribute('role') && node.getAttribute('role') === 'article')
                    || (mobile && node.getAttribute('data-sigil') && node.getAttribute('data-sigil') === 'comments-preview') ) ) {
                foundItem = node;
                break;
            }
            if (node.parentElement) {
                node = node.parentElement;
            } else {
                console.log('no parent comment or reply could be found for author '+authorName);
                break;
            }
        }
        if (foundItem === null) {
            console.log('no parent comment or reply could be found for author '+authorName);
            continue;
        }
        let firstItemEval = firstEval;
        if (node !== article) {
            firstItemEval = {{JS_PREFIX}}_mark_evaluated(foundItem);
        }
        if ({{JS_PREFIX}}_is_ad(foundItem)) {
            // log('removing ad ('+authorDisplayName+')');
            {{JS_PREFIX}}_tally_author_block(authorName == null ? {{PAGE_PREFIX}}_msg_or_default({{JS_PREFIX}}_messages, 'web_advertOrOtherBlock', 'ad/other') : authorName);
            if (!firstItemEval) {{JS_PREFIX}}_untally_allow();
            return {item: foundItem, author: authorName};

        } else {
            const blocked = {{JS_PREFIX}}_block_or_decorate(firstEval, foundItem, authorLink, authorName, authorDisplay, blocked_users, 16);
            if (blocked) {
                if (node === article) return blocked;
                {{JS_PREFIX}}_tally_author_block(authorName == null ? {{PAGE_PREFIX}}_msg_or_default({{JS_PREFIX}}_messages, 'web_advertOrOtherBlock', 'ad/other') : authorName);
                if (!firstItemEval) {{JS_PREFIX}}_untally_allow();

            } else if (node !== article && firstItemEval) {
                {{JS_PREFIX}}_tally_allow();
            }
        }
    }
    if (firstEval) {
        // console.log('>>> allowing post with firstAuthor = '+firstAuthor);
        {{JS_PREFIX}}_tally_allow();
    }
    return null;
}

function {{JS_PREFIX}}_div_is_comment(div) {
    return div.getAttribute('data-sigil') === 'comment';
}

function {{JS_PREFIX}}_div_is_comment_reply(div) {
    return div.getAttribute('data-sigil') === 'comment inline-reply';
}

function {{JS_PREFIX}}_find_story_comments() {
    const path = window.location.pathname;
    let containerId = null;
    if (path.startsWith('/story.php')) {
        containerId = 'm_story_permalink_view';
    } else if (path.startsWith('/photo.php')) {
        containerId = 'MPhotoLowerContent';
    } else {
        console.log("unknown story type: "+ path)
        return [];
    }
    const container = document.getElementById(containerId);
    if (container) {
        return Array.from(container.getElementsByTagName('div'))
            .filter(div => {{JS_PREFIX}}_div_is_comment(div));
    } else if (container.length > 1) {
        console.log('container not found: '+containerId);
        return [];
    }
}

function {{JS_PREFIX}}_apply_blocks(blocked_users) {

    const mobile = {{JS_PREFIX}}_mobile;
    const log = {{PAGE_PREFIX}}_log;

    if (window.location.pathname.startsWith('/story.php') || window.location.pathname.startsWith('/photo.php')) {
        const comments = mobile
            ? {{JS_PREFIX}}_find_story_comments()
            : [];  // todo for desktop
        comments.forEach(comment => {
            try {
                const block = {{JS_PREFIX}}_should_block_comment(blocked_users, comment);
                if (block) {
                    {{JS_PREFIX}}_remove_item(block.item, block.author);
                }
            } catch (e) {
                console.log('error processing comment: '+e);
            }
        });
    } else {
        const articles = mobile
            ? {{JS_PREFIX}}_getElementsByXPath('//article')
            : Array.from({{JS_PREFIX}}_getElementsByXPath('//div[@role="article" and @aria-posinset]'));

        for (let i=0; i<articles.length; i++) {
            const article = articles[i];
            const block = {{JS_PREFIX}}_should_block(blocked_users, article);
            if (block) {
                {{JS_PREFIX}}_remove_item(block.item, block.author);
            }
            Array.from(article.getElementsByTagName('a')).forEach(a => {
                let href =  a.href;
                if (typeof href !== 'string' || href.length === 0) return;
                if (a.className && a.className.indexOf('{{JS_PREFIX}}_fb_scrubbed') !== -1) return;
                if (a.className) {
                    a.className = a.className + ' {{JS_PREFIX}}_fb_scrubbed';
                } else {
                    a.className = '{{JS_PREFIX}}_fb_scrubbed';
                }

                if (href.indexOf('facebook.com') !== -1) {
                    if ({{JS_PREFIX}}_is_author_link(a.href) && a.href.indexOf('?') !== -1) {
                        {{JS_PREFIX}}_clean_author_link(a);

                    } else if (href.indexOf('u=http') !== -1) {
                        const uPos = href.indexOf('u=http');
                        const andPos = href.indexOf('&');
                        if (andPos !== -1) {
                            href = href.substring(uPos + 2, andPos);
                        } else {
                            href = href.substring(uPos + 2);
                        }
                        href = decodeURIComponent(href);
                    }
                }
                href = {{PAGE_PREFIX}}_remove_param(href, 'refid');
                href = {{PAGE_PREFIX}}_remove_param(href, '_ft_');
                href = {{PAGE_PREFIX}}_remove_param(href, '__tn__');

                let offSite = href.indexOf('facebook.com/') === -1;
                if (offSite) {
                    href = {{PAGE_PREFIX}}_remove_param(href, 'fbclid');
                    a.removeAttribute('data-gt');
                    a.removeAttribute('data-sigil');
                    a.href = href;
                    {{JS_PREFIX}}_chase_redirects(a, false);
                } else {
                    a.href = href;
                }
            });
        }
    }
    if (!mobile) {
        const sponsored = {{JS_PREFIX}}_getElementsByXPath('//h3/span[text()="Sponsored"]');
        if (sponsored && sponsored.length > 0) {
            try {
                sponsored[0].parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.innerHTML = '';
            } catch (e) {
                console.log('error clearing sponsored content');
            }
        }
    }
    // localStorage.clear();
}
