const Plugin = require('../plugin');

let getChannel, g_dc, g_cat, ha, disp, chanM, fm, reb, sv, cs, csp, ghp, gs, gsr, pf, sw = {}, g = {}, ai = {};

// copied from Discord's minified JS
function N(e,o,l,n){let r;r||(r="function"==typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103);const t=e&&e.defaultProps,f=arguments.length-3;if(o||0===f||(o={children:void 0}),o&&t)for(const e in t)void 0===o[e]&&(o[e]=t[e]);else o||(o=t||{});if(1===f)o.children=n;else if(f>1){const e=new Array(f);for(let o=0;o<f;o++)e[o]=arguments[o+3];o.children=e}return{$$typeof:r,type:e,key:void 0===l?null:""+l,ref:null,props:o,_owner:null}}

module.exports = new Plugin({
    name: 'Hidden Channels',
    description: 'Shows hidden channels and lets you view server permissions.',
    color: 'magenta',
    author: 'Joe 🎸#7070',

    load: async function() {
        disp = window.EDApi.findModule("dispatch");
        getChannel = window.EDApi.findModule('getChannel').getChannel;
        sw = window.EDApi.findModule('switchItem');
        g = window.EDApi.findModule(m => m.group && m.item);
        ai = window.EDApi.findModule('actionIcon');

        const getUser = window.EDApi.findModule('getCurrentUser').getCurrentUser;
        const getAllChannels = window.EDApi.findModule('getChannels').getChannels;
        const can = window.EDApi.findModule('computePermissions').can;

        g_dc = window.EDApi.findModule('getDefaultChannel');
        window.EDApi.monkeyPatch(g_dc, 'getChannels', b => {
            const og = b.callOriginalMethod(b.methodArguments);
            if (!b.methodArguments[0]) return og;
            const hidden = [], allChans = getAllChannels();
            for (const i in allChans) {
                if (allChans[i].guild_id === b.methodArguments[0]) {
                    if (allChans[i].type !== 4 && !can(1024, getUser(), getChannel(allChans[i].id))) {
                        hidden.push(allChans[i]);
                    }
                }
            }
            og.HIDDEN = hidden;
            return og;
        });
        chanM = window.EDApi.findModule(m => m.prototype && m.prototype.isManaged);
        chanM.prototype.isHidden = function() {
            return [0, 4, 5].includes(this.type) && !can(1024, getUser(), this);
        }

        g_cat = window.EDApi.findModule(m => m.getCategories && !m.EMOJI_NAME_RE);
        window.EDApi.monkeyPatch(g_cat, 'getCategories', b => {
            const og = b.callOriginalMethod(b.methodArguments);
            const chs = g_dc.getChannels(b.methodArguments[0]);
            chs.HIDDEN.forEach(c => {
                const result = og[c.parent_id || "null"].filter(item => item.channel.id === c.id);
                if (result.length) return; // already added
                og[c.parent_id || "null"].push({channel: c, index: 0})
            });
            return og;
        });

        ha = window.EDApi.findModule('hasUnread').__proto__;
        window.EDApi.monkeyPatch(ha, 'hasUnread', function(b) {
            if (getChannel(b.methodArguments[0]) && getChannel(b.methodArguments[0]).isHidden())
                return false; // don't show hidden channels as unread.
            return b.callOriginalMethod(b.methodArguments);
        });
        window.EDApi.monkeyPatch(ha, 'hasUnreadPins', function(b) {
            if (getChannel(b.methodArguments[0]) && getChannel(b.methodArguments[0]).isHidden())
                return false; // don't show icon on hidden channel pins.
            return b.callOriginalMethod(b.methodArguments);
        });

        disp.subscribe("CHANNEL_SELECT", module.exports.dispatchSubscription);

        fm = window.EDApi.findModule("fetchMessages");
        window.EDApi.monkeyPatch(fm, "fetchMessages", function(b) {
            if (getChannel(b.methodArguments[0]) && getChannel(b.methodArguments[0]).isHidden()) return;
            return b.callOriginalMethod(b.methodArguments);
        });

        const clk = window.EDApi.findModuleByDisplayName("Clickable")
        //const icon = window.EDApi.findModuleByDisplayName("Icon");

        reb = window.EDApi.findModule(m => m.default && m.default.prototype && m.default.prototype.renderEditButton).default.prototype;
        /*window.EDApi.monkeyPatch(reb, "renderEditButton", function(b) {
            return N(clk, {
                className: ai.iconItem,
                onClick: function() {
                    module.exports._editingGuild = null;
                    module.exports._editingChannel = b.thisObject.props.channel.id;
                    return b.thisObject.handleEditClick.apply(b.thisObject, arguments);
                },
                onMouseEnter: b.thisObject.props.onMouseEnter,
                onMouseLeave: b.thisObject.props.onMouseLeave
            }, void 0, N(icon, {
                name: "Gear",
                width: 16,
                height: 16,
                className: ai.actionIcon
            }));
        });*/

        sv = window.EDApi.findModuleByDisplayName("SettingsView").prototype;
        window.EDApi.monkeyPatch(sv, 'getPredicateSections', {before: b => {
            const permSect = b.thisObject.props.sections.find(item => item.section === 'PERMISSIONS');
            if (permSect) permSect.predicate = () => true;
        }, silent: true});

        cs = window.EDApi.findModuleByDisplayName("FluxContainer(ChannelSettings)").prototype;
        window.EDApi.monkeyPatch(cs, 'render', b => {
            const egg = b.callOriginalMethod(b.methodArguments);
            egg.props.canManageRoles = true;
            return egg;
        });

        csp = window.EDApi.findModuleByDisplayName("FluxContainer(ChannelSettingsPermissions)").prototype;
        window.EDApi.monkeyPatch(csp, 'render', b => {
            const egg = b.callOriginalMethod(b.methodArguments);
            const chan = getChannel(egg.props.channel.id);
            if (!chan || !chan.isHidden()) return egg;
            egg.props.canSyncChannel = false;
            egg.props.locked = true;
            setTimeout(() => {
                document.querySelectorAll('.'+g.group).forEach(elem => elem.style = "opacity: 0.5; pointer-events: none;");
            });
            return egg;
        });

        ghp = window.EDApi.findModuleByDisplayName("FluxContainer(GuildHeaderPopout)").prototype;
        window.EDApi.monkeyPatch(ghp, 'render', b => {
            const egg = b.callOriginalMethod(b.methodArguments);
            egg.props.canAccessSettings = true;
            return egg;
        });

        gs = window.EDApi.findModuleByDisplayName("FluxContainer(GuildSettings)").prototype;
        window.EDApi.monkeyPatch(gs, 'render', b => {
            const egg = b.callOriginalMethod(b.methodArguments);
            module.exports._editingChannel = null;
            module.exports._editingGuild = egg.props.guild.id;
            egg.props.canManageRoles = true;
            return egg;
        });

        const cancan = window.EDApi.findModuleByProps('can', 'canUser').can;
        gsr = window.EDApi.findModuleByDisplayName("FluxContainer(GuildSettingsRoles)").prototype;
        window.EDApi.monkeyPatch(gsr, 'render', b => {
            const egg = b.callOriginalMethod(b.methodArguments);
            const hasPerm = cancan(268435456, { guildId: egg.props.guild.id });
            if (hasPerm) return;
            setTimeout(() => {
                document.querySelectorAll('.'+sw.switchItem).forEach(elem => elem.classList.add(sw.disabled));
            });
            return egg;
        });

        const getGuild = window.EDApi.findModule('getGuild').getGuild;
        pf = window.EDApi.findModuleByDisplayName("PermissionsForm").prototype;
        window.EDApi.monkeyPatch(pf, 'render', b => {
            const egg = b.callOriginalMethod(b.methodArguments);
            const guild = module.exports._editingGuild ? getGuild(module.exports._editingGuild) : null;
            const channel = module.exports._editingChannel ? getChannel(module.exports._editingChannel) : null;
            if (!guild && !channel) return egg;
            const hasPerm = cancan(268435456, guild ? { guildId: guild.id } : { channelId: channel.id });
            if (hasPerm) return;

            if (!egg.props.children || !egg.props.children[1]) return egg;
            egg.props.children[1].forEach(item => {item.disabled = true; item.props.disabled = true;});
            return egg;
        });
    },
    unload: function() {
        g_dc.getChannels.unpatch();
        g_cat.getCategories.unpatch();
        ha.hasUnread.unpatch();
        ha.hasUnreadPins.unpatch();
        fm.fetchMessages.unpatch();
        reb.renderEditButton.unpatch();

        for (const mod of [sv, cs, csp, ghp, gs, gsr, pf])
            if (mod && mod.render && mod.render.unpatch) mod.render.unpatch();

        disp.unsubscribe("CHANNEL_SELECT", module.exports.dispatchSubscription);
    },
    dispatchSubscription: function (data) {
        if (data.type !== "CHANNEL_SELECT") return;

        if (getChannel(data.channelId) && getChannel(data.channelId).isHidden()) {
            setTimeout(module.exports.attachHiddenChanNotice);
        }
    },
    attachHiddenChanNotice: function () {
        const messagesWrapper = document.querySelector(`.${window.EDApi.findModule("messages").messagesWrapper}`);
        if (!messagesWrapper) return;

        messagesWrapper.firstChild.style.display = "none"; // Remove messages shit.
        messagesWrapper.parentElement.children[1].style.display = "none"; // Remove message box.
        messagesWrapper.parentElement.parentElement.children[1].style.display = "none"; // Remove user list.

        const toolbar = document.querySelector("."+window.EDApi.findModule(m => {
            if (m instanceof Window) return;
            if (m.toolbar && m.selected) return m;
        }).toolbar);

        toolbar.style.display = "none";

        const hiddenChannelNotif = document.createElement("div");

        // Class name modules
        const txt = window.EDApi.findModule("h5");
        const flx = window.EDApi.findModule("flex");

        hiddenChannelNotif.className = flx.flexCenter;
        hiddenChannelNotif.style.width = "100%";

        hiddenChannelNotif.innerHTML = `
        <div class="${flx.flex} ${flx.directionColumn} ${flx.alignCenter}">
        <h2 class="${txt.h2} ${txt.defaultColor}">This is a hidden channel.</h2>
        <h5 class="${txt.h5} ${txt.defaultColor}">You cannot see the contents of this channel. However, you may see its name and topic.</h5>
        </div>`;

        messagesWrapper.appendChild(hiddenChannelNotif);
    }
});
