"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const electron_better_ipc_1 = require("electron-better-ipc");
const electron_util_1 = require("electron-util");
const elementReady = require("element-ready");
const selectors_1 = require("./browser/selectors");
const config_1 = require("./config");
const autoplay_1 = require("./autoplay");
const conversation_list_1 = require("./browser/conversation-list");
const selectedConversationSelector = '._5l-3._1ht1._1ht2';
const preferencesSelector = '._10._4ebx.uiLayer._4-hy';
const messengerSoundsSelector = `${preferencesSelector} ._374d ._6bkz`;
const conversationMenuSelector = '.uiLayer:not(.hidden_elem) [role=menu]';
async function withMenu(menuButtonElement, callback) {
    const { classList } = document.documentElement;
    // Prevent the dropdown menu from displaying
    classList.add('hide-dropdowns');
    // Click the menu button
    menuButtonElement.click();
    // Wait for the menu to close before removing the 'hide-dropdowns' class
    const menuLayer = document.querySelector('.uiContextualLayerPositioner:not(.hidden_elem)');
    if (menuLayer) {
        const observer = new MutationObserver(() => {
            if (menuLayer.classList.contains('hidden_elem')) {
                classList.remove('hide-dropdowns');
                observer.disconnect();
            }
        });
        observer.observe(menuLayer, { attributes: true, attributeFilter: ['class'] });
    }
    else {
        // Fallback in case .uiContextualLayerPositioner is missing
        classList.remove('hide-dropdowns');
    }
    await callback();
}
async function withSettingsMenu(callback) {
    const settingsMenu = (await elementReady('._30yy._6ymd._2agf,._30yy._2fug._p', {
        stopOnDomReady: false
    }));
    await withMenu(settingsMenu, callback);
}
function selectMenuItem(itemNumber) {
    const selector = document.querySelector(`${conversationMenuSelector} > li:nth-child(${itemNumber}) a`);
    if (selector) {
        selector.click();
    }
}
async function selectOtherListViews(itemNumber) {
    // In case one of other views is shown
    clickBackButton();
    await withSettingsMenu(() => {
        selectMenuItem(itemNumber);
    });
}
function clickBackButton() {
    const backButton = document.querySelector('._30yy._2oc9');
    if (backButton) {
        backButton.click();
    }
}
electron_better_ipc_1.ipcRenderer.answerMain('show-preferences', async () => {
    if (isPreferencesOpen()) {
        return;
    }
    await openPreferences();
});
electron_better_ipc_1.ipcRenderer.answerMain('new-conversation', () => {
    document.querySelector('._30yy[data-href$="/new"]').click();
});
electron_better_ipc_1.ipcRenderer.answerMain('log-out', async () => {
    if (config_1.default.get('useWorkChat')) {
        document.querySelector('._5lxs._3qct._p').click();
        // Menu creation is slow
        setTimeout(() => {
            const nodes = document.querySelectorAll('._54nq._9jo._558b._2n_z li:last-child a');
            nodes[nodes.length - 1].click();
        }, 250);
    }
    else {
        await withSettingsMenu(() => {
            const nodes = document.querySelectorAll('._54nq._2i-c._558b._2n_z li:last-child a');
            nodes[nodes.length - 1].click();
        });
    }
});
electron_better_ipc_1.ipcRenderer.answerMain('find', () => {
    document.querySelector('._58al').focus();
});
electron_better_ipc_1.ipcRenderer.answerMain('search', () => {
    document.querySelector('._3szo:nth-of-type(1)').click();
});
electron_better_ipc_1.ipcRenderer.answerMain('insert-gif', () => {
    var _a;
    const gifElement = (_a = 
    // Old UI
    document.querySelector('._yht')) !== null && _a !== void 0 ? _a : 
    // New UI
    [...document.querySelectorAll('._7oam')].find(element => element.querySelector('svg path[d^="M27.002,13.5"]'));
    gifElement.click();
});
electron_better_ipc_1.ipcRenderer.answerMain('insert-emoji', async () => {
    const emojiElement = (await elementReady('._5s2p, ._30yy._7odb', {
        stopOnDomReady: false
    }));
    emojiElement.click();
});
electron_better_ipc_1.ipcRenderer.answerMain('insert-sticker', () => {
    var _a;
    const stickerElement = (_a = 
    // Old UI
    document.querySelector('._4rv6')) !== null && _a !== void 0 ? _a : 
    // New UI
    [...document.querySelectorAll('._7oam')].find(element => element.querySelector('svg path[d^="M22.5,18.5 L27.998,18.5"]'));
    stickerElement.click();
});
electron_better_ipc_1.ipcRenderer.answerMain('attach-files', () => {
    document
        .querySelector('._5vn8 + input[type="file"], ._7oam input[type="file"]')
        .click();
});
electron_better_ipc_1.ipcRenderer.answerMain('focus-text-input', () => {
    document.querySelector('._7kpg ._5rpu').focus();
});
electron_better_ipc_1.ipcRenderer.answerMain('next-conversation', nextConversation);
electron_better_ipc_1.ipcRenderer.answerMain('previous-conversation', previousConversation);
electron_better_ipc_1.ipcRenderer.answerMain('mute-conversation', async () => {
    await openMuteModal();
});
electron_better_ipc_1.ipcRenderer.answerMain('delete-conversation', async () => {
    await deleteSelectedConversation();
});
electron_better_ipc_1.ipcRenderer.answerMain('hide-conversation', async () => {
    const index = selectedConversationIndex();
    if (index !== -1) {
        await hideSelectedConversation();
        const key = index + 1;
        await jumpToConversation(key);
    }
});
async function openHiddenPreferences() {
    if (!isPreferencesOpen()) {
        const style = document.createElement('style');
        // Hide both the backdrop and the preferences dialog
        style.textContent = `${preferencesSelector} ._3ixn, ${preferencesSelector} ._59s7 { opacity: 0 !important }`;
        document.body.append(style);
        await openPreferences();
        // Will clean up itself after the preferences are closed
        document.querySelector(preferencesSelector).append(style);
        return true;
    }
    return false;
}
async function toggleSounds(checked) {
    const shouldClosePreferences = await openHiddenPreferences();
    const soundsCheckbox = document.querySelector(messengerSoundsSelector);
    if (typeof checked === 'undefined' || checked !== soundsCheckbox.checked) {
        soundsCheckbox.click();
    }
    if (shouldClosePreferences) {
        closePreferences();
    }
}
electron_better_ipc_1.ipcRenderer.answerMain('toggle-sounds', toggleSounds);
electron_better_ipc_1.ipcRenderer.answerMain('toggle-mute-notifications', async (defaultStatus) => {
    const shouldClosePreferences = await openHiddenPreferences();
    const notificationCheckbox = document.querySelector(selectors_1.default.notificationCheckbox);
    if (defaultStatus === undefined) {
        notificationCheckbox.click();
    }
    else if ((defaultStatus && notificationCheckbox.checked) ||
        (!defaultStatus && !notificationCheckbox.checked)) {
        notificationCheckbox.click();
    }
    if (shouldClosePreferences) {
        closePreferences();
    }
    return !notificationCheckbox.checked;
});
electron_better_ipc_1.ipcRenderer.answerMain('toggle-message-buttons', () => {
    document.body.classList.toggle('show-message-buttons', config_1.default.get('showMessageButtons'));
});
electron_better_ipc_1.ipcRenderer.answerMain('show-active-contacts-view', async () => {
    await selectOtherListViews(3);
});
electron_better_ipc_1.ipcRenderer.answerMain('show-message-requests-view', async () => {
    await selectOtherListViews(4);
});
electron_better_ipc_1.ipcRenderer.answerMain('show-hidden-threads-view', async () => {
    await selectOtherListViews(5);
});
electron_better_ipc_1.ipcRenderer.answerMain('toggle-unread-threads-view', async () => {
    await selectOtherListViews(6);
});
electron_better_ipc_1.ipcRenderer.answerMain('toggle-video-autoplay', () => {
    autoplay_1.toggleVideoAutoplay();
});
electron_better_ipc_1.ipcRenderer.answerMain('reload', () => {
    location.reload();
});
function setDarkMode() {
    if (electron_util_1.is.macos && config_1.default.get('followSystemAppearance')) {
        electron_util_1.api.nativeTheme.themeSource = 'system';
    }
    else {
        electron_util_1.api.nativeTheme.themeSource = config_1.default.get('darkMode') ? 'dark' : 'light';
    }
    document.documentElement.classList.toggle('dark-mode', electron_util_1.api.nativeTheme.shouldUseDarkColors);
    updateVibrancy();
}
function setPrivateMode() {
    document.documentElement.classList.toggle('private-mode', config_1.default.get('privateMode'));
    if (electron_util_1.is.macos) {
        conversation_list_1.sendConversationList();
    }
}
function updateVibrancy() {
    const { classList } = document.documentElement;
    classList.remove('sidebar-vibrancy', 'full-vibrancy');
    switch (config_1.default.get('vibrancy')) {
        case 'sidebar':
            classList.add('sidebar-vibrancy');
            break;
        case 'full':
            classList.add('full-vibrancy');
            break;
        default:
    }
    electron_better_ipc_1.ipcRenderer.callMain('set-vibrancy');
}
function updateSidebar() {
    const { classList } = document.documentElement;
    classList.remove('sidebar-hidden', 'sidebar-force-narrow', 'sidebar-force-wide');
    switch (config_1.default.get('sidebar')) {
        case 'hidden':
            classList.add('sidebar-hidden');
            break;
        case 'narrow':
            classList.add('sidebar-force-narrow');
            break;
        case 'wide':
            classList.add('sidebar-force-wide');
            break;
        default:
    }
}
async function updateDoNotDisturb() {
    const shouldClosePreferences = await openHiddenPreferences();
    const soundsCheckbox = document.querySelector(messengerSoundsSelector);
    if (shouldClosePreferences) {
        closePreferences();
    }
    toggleSounds(await electron_better_ipc_1.ipcRenderer.callMain('update-dnd-mode', soundsCheckbox.checked));
}
function renderOverlayIcon(messageCount) {
    const canvas = document.createElement('canvas');
    canvas.height = 128;
    canvas.width = 128;
    canvas.style.letterSpacing = '-5px';
    const ctx = canvas.getContext('2d');
    ctx.fillStyle = '#f42020';
    ctx.beginPath();
    ctx.ellipse(64, 64, 64, 64, 0, 0, 2 * Math.PI);
    ctx.fill();
    ctx.textAlign = 'center';
    ctx.fillStyle = 'white';
    ctx.font = '90px sans-serif';
    ctx.fillText(String(Math.min(99, messageCount)), 64, 96);
    return canvas;
}
electron_better_ipc_1.ipcRenderer.answerMain('update-sidebar', () => {
    updateSidebar();
});
electron_better_ipc_1.ipcRenderer.answerMain('set-dark-mode', setDarkMode);
electron_better_ipc_1.ipcRenderer.answerMain('set-private-mode', setPrivateMode);
electron_better_ipc_1.ipcRenderer.answerMain('update-vibrancy', () => {
    updateVibrancy();
});
electron_better_ipc_1.ipcRenderer.answerMain('render-overlay-icon', (messageCount) => {
    return {
        data: renderOverlayIcon(messageCount).toDataURL(),
        text: String(messageCount)
    };
});
electron_better_ipc_1.ipcRenderer.answerMain('render-native-emoji', (emoji) => {
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    canvas.width = 256;
    canvas.height = 256;
    context.textAlign = 'center';
    context.textBaseline = 'middle';
    if (electron_util_1.is.macos) {
        context.font = '256px system-ui';
        context.fillText(emoji, 128, 154);
    }
    else {
        context.textBaseline = 'bottom';
        context.font = '225px system-ui';
        context.fillText(emoji, 128, 256);
    }
    const dataUrl = canvas.toDataURL();
    return dataUrl;
});
electron_better_ipc_1.ipcRenderer.answerMain('zoom-reset', () => {
    setZoom(1);
});
electron_better_ipc_1.ipcRenderer.answerMain('zoom-in', () => {
    const zoomFactor = config_1.default.get('zoomFactor') + 0.1;
    if (zoomFactor < 1.6) {
        setZoom(zoomFactor);
    }
});
electron_better_ipc_1.ipcRenderer.answerMain('zoom-out', () => {
    const zoomFactor = config_1.default.get('zoomFactor') - 0.1;
    if (zoomFactor >= 0.8) {
        setZoom(zoomFactor);
    }
});
electron_better_ipc_1.ipcRenderer.answerMain('jump-to-conversation', async (key) => {
    await jumpToConversation(key);
});
async function nextConversation() {
    const index = selectedConversationIndex(1);
    if (index !== -1) {
        await selectConversation(index);
    }
}
async function previousConversation() {
    const index = selectedConversationIndex(-1);
    if (index !== -1) {
        await selectConversation(index);
    }
}
async function jumpToConversation(key) {
    const index = key - 1;
    await selectConversation(index);
}
// Focus on the conversation with the given index
async function selectConversation(index) {
    const list = await elementReady(selectors_1.default.conversationList, { stopOnDomReady: false });
    if (!list) {
        console.error('Could not find conversations list', selectors_1.default.conversationList);
        return;
    }
    const conversation = list.children[index];
    if (!conversation) {
        console.error('Could not find conversation', index);
        return;
    }
    conversation.firstChild.firstChild.click();
}
function selectedConversationIndex(offset = 0) {
    const selected = document.querySelector(selectedConversationSelector);
    if (!selected) {
        return -1;
    }
    const list = [...selected.parentNode.children];
    const index = list.indexOf(selected) + offset;
    return ((index % list.length) + list.length) % list.length;
}
function setZoom(zoomFactor) {
    const node = document.querySelector('#zoomFactor');
    node.textContent = `${selectors_1.default.conversationSelector} {zoom: ${zoomFactor} !important}`;
    config_1.default.set('zoomFactor', zoomFactor);
}
async function withConversationMenu(callback) {
    const menuButton = document.querySelector(`${selectedConversationSelector} [aria-haspopup=true] [role=button]`);
    if (menuButton) {
        await withMenu(menuButton, callback);
    }
}
async function openMuteModal() {
    await withConversationMenu(() => {
        selectMenuItem(1);
    });
}
/*
This function assumes:
- There is a selected conversation.
- That the conversation already has its conversation menu open.

In other words, you should only use this function within a callback that is provided to `withConversationMenu()`, because `withConversationMenu()` makes sure to have the conversation menu open before executing the callback and closes the conversation menu afterwards.
*/
function isSelectedConversationGroup() {
    const separator = document.querySelector(`${conversationMenuSelector} > li:nth-child(6)[role=separator]`);
    return Boolean(separator);
}
async function hideSelectedConversation() {
    await withConversationMenu(() => {
        selectMenuItem(isSelectedConversationGroup() ? 4 : 3);
    });
}
async function deleteSelectedConversation() {
    await withConversationMenu(() => {
        selectMenuItem(isSelectedConversationGroup() ? 5 : 4);
    });
}
async function openPreferences() {
    await withSettingsMenu(() => {
        selectMenuItem(1);
    });
    await elementReady(preferencesSelector, { stopOnDomReady: false });
}
function isPreferencesOpen() {
    return Boolean(document.querySelector('._3quh._30yy._2t_._5ixy'));
}
function closePreferences() {
    const doneButton = document.querySelector('._3quh._30yy._2t_._5ixy');
    doneButton.click();
}
function insertionListener(event) {
    if (event.animationName === 'nodeInserted' && event.target) {
        event.target.dispatchEvent(new Event('mouseover', { bubbles: true }));
    }
}
async function observeAutoscroll() {
    const mainElement = await elementReady('._4sp8', { stopOnDomReady: false });
    if (!mainElement) {
        return;
    }
    const scrollToBottom = () => {
        const scrollableElement = document.querySelector('[role=presentation] .scrollable');
        if (scrollableElement) {
            scrollableElement.scroll({
                top: Number.MAX_SAFE_INTEGER,
                behavior: 'smooth'
            });
        }
    };
    const hookMessageObserver = async () => {
        const chatElement = await elementReady('[role=presentation] .scrollable [role = region] > div[id ^= "js_"]', { stopOnDomReady: false });
        if (chatElement) {
            // Scroll to the bottom when opening different conversation
            scrollToBottom();
            const messageObserver = new MutationObserver((record) => {
                const newMessages = record.filter(record => {
                    // The mutation is an addition
                    return record.addedNodes.length > 0 &&
                        // ... of a div       (skip the "seen" status change)
                        record.addedNodes[0].tagName === 'DIV' &&
                        // ... on the last child       (skip previous messages added when scrolling up)
                        chatElement.lastChild.contains(record.target);
                });
                if (newMessages.length > 0) {
                    // Scroll to the bottom when there are new messages
                    scrollToBottom();
                }
            });
            messageObserver.observe(chatElement, { childList: true, subtree: true });
        }
    };
    hookMessageObserver();
    // Hook it again if conversation changes
    const conversationObserver = new MutationObserver(hookMessageObserver);
    conversationObserver.observe(mainElement, { childList: true });
}
// Listen for emoji element dom insertion
document.addEventListener('animationstart', insertionListener, false);
// Inject a global style node to maintain custom appearance after conversation change or startup
document.addEventListener('DOMContentLoaded', async () => {
    const style = document.createElement('style');
    style.id = 'zoomFactor';
    document.body.append(style);
    // Set the zoom factor if it was set before quitting
    const zoomFactor = config_1.default.get('zoomFactor');
    setZoom(zoomFactor);
    // Enable OS specific styles
    document.documentElement.classList.add(`os-${process.platform}`);
    // Restore sidebar view state to what is was set before quitting
    updateSidebar();
    // Activate Dark Mode if it was set before quitting
    setDarkMode();
    // Activate Private Mode if it was set before quitting
    setPrivateMode();
    // Configure do not disturb
    if (electron_util_1.is.macos) {
        await updateDoNotDisturb();
    }
    // Prevent flash of white on startup when in dark mode
    // TODO: find a CSS-only solution
    if (!electron_util_1.is.macos && config_1.default.get('darkMode')) {
        document.documentElement.style.backgroundColor = '#1e1e1e';
    }
    // Disable autoplay if set in settings
    autoplay_1.toggleVideoAutoplay();
    // Hook auto-scroll observer
    observeAutoscroll();
});
// Handle title bar double-click.
window.addEventListener('dblclick', (event) => {
    const target = event.target;
    const titleBar = target.closest('._36ic._5l-3,._5742,._6-xk,._673w');
    if (!titleBar) {
        return;
    }
    electron_better_ipc_1.ipcRenderer.callMain('titlebar-doubleclick');
}, {
    passive: true
});
window.addEventListener('load', () => {
    if (location.pathname.startsWith('/login')) {
        const keepMeSignedInCheckbox = document.querySelector('#u_0_0');
        keepMeSignedInCheckbox.checked = config_1.default.get('keepMeSignedIn');
        keepMeSignedInCheckbox.addEventListener('change', () => {
            config_1.default.set('keepMeSignedIn', !config_1.default.get('keepMeSignedIn'));
        });
    }
});
// Toggles styles for inactive window
window.addEventListener('blur', () => {
    document.documentElement.classList.add('is-window-inactive');
});
window.addEventListener('focus', () => {
    document.documentElement.classList.remove('is-window-inactive');
});
// It's not possible to add multiple accelerators
// so this needs to be done the old-school way
document.addEventListener('keydown', async (event) => {
    // The `!event.altKey` part is a workaround for https://github.com/electron/electron/issues/13895
    const combineKey = electron_util_1.is.macos ? event.metaKey : event.ctrlKey && !event.altKey;
    if (!combineKey) {
        return;
    }
    if (event.key === ']') {
        await nextConversation();
    }
    if (event.key === '[') {
        await previousConversation();
    }
    const number = Number.parseInt(event.code.slice(-1), 10);
    if (number >= 1 && number <= 9) {
        await jumpToConversation(number);
    }
});
// Pass events sent via `window.postMessage` on to the main process
window.addEventListener('message', async ({ data: { type, data } }) => {
    if (type === 'notification') {
        showNotification(data);
    }
    if (type === 'notification-reply') {
        await sendReply(data.reply);
        if (data.previousConversation) {
            await selectConversation(data.previousConversation);
        }
    }
});
function showNotification({ id, title, body, icon, silent }) {
    const image = new Image();
    image.crossOrigin = 'anonymous';
    image.src = icon;
    image.addEventListener('load', () => {
        const canvas = document.createElement('canvas');
        const context = canvas.getContext('2d');
        canvas.width = image.width;
        canvas.height = image.height;
        context.drawImage(image, 0, 0, image.width, image.height);
        electron_better_ipc_1.ipcRenderer.callMain('notification', {
            id,
            title,
            body,
            icon: canvas.toDataURL(),
            silent
        });
    });
}
async function sendReply(message) {
    const inputField = document.querySelector('[contenteditable="true"]');
    if (!inputField) {
        return;
    }
    const previousMessage = inputField.textContent;
    // Send message
    inputField.focus();
    insertMessageText(message, inputField);
    const sendButton = await elementReady('._30yy._38lh', { stopOnDomReady: false });
    if (!sendButton) {
        console.error('Could not find send button');
        return;
    }
    sendButton.click();
    // Restore (possible) previous message
    if (previousMessage) {
        insertMessageText(previousMessage, inputField);
    }
}
function insertMessageText(text, inputField) {
    // Workaround: insert placeholder value to get execCommand working
    if (!inputField.textContent) {
        const event = document.createEvent('TextEvent');
        event.initTextEvent('textInput', true, true, window, '_', 0, '');
        inputField.dispatchEvent(event);
    }
    document.execCommand('selectAll', false, undefined);
    document.execCommand('insertText', false, text);
}
electron_better_ipc_1.ipcRenderer.answerMain('notification-callback', (data) => {
    window.postMessage({ type: 'notification-callback', data }, '*');
});
electron_better_ipc_1.ipcRenderer.answerMain('notification-reply-callback', (data) => {
    const previousConversation = selectedConversationIndex();
    data.previousConversation = previousConversation;
    window.postMessage({ type: 'notification-reply-callback', data }, '*');
});
