Popmundo - Bulk Offer & Accept Helper

Oferta itens por nome/quantidade/preço e aceita ofertas/presentes/compras em massa por nome e preço máximo (apenas valores inteiros).

// ==UserScript==
// @name         Popmundo - Bulk Offer & Accept Helper
// @namespace    http://tampermonkey.net/
// @version      4.0
// @description  Oferta itens por nome/quantidade/preço e aceita ofertas/presentes/compras em massa por nome e preço máximo (apenas valores inteiros). 
// @author       Popper
// @match        *://*.popmundo.com/World/Popmundo.aspx/Character/OfferItem/*
// @match        *://*.popmundo.com/World/Popmundo.aspx/Character/ItemsOffered
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @run-at       document-idle
// ==/UserScript==
(function() {
    'use strict';
    // =================================================================================
    // --- ROTEADOR PRINCIPAL ---
    // =================================================================================
    function initializeScript() {
        const currentUrl = window.location.href;
        if (currentUrl.includes('/Character/OfferItem/')) {
            console.log("Bulk Helper: Página de OFERTAR item detectada.");
            setupOfferPage();
        } else if (currentUrl.includes('/Character/ItemsOffered')) {
            console.log("Bulk Helper: Página de ACEITAR ofertas detectada.");
            setupAcceptPage();
        }
    }

    // =================================================================================
    // --- FUNCIONALIDADE 1: OFERTAR ITENS EM MASSA (LAYOUT CORRIGIDO) ---
    // =================================================================================
    function setupOfferPage() {
        const OFFER_BUTTON_SELECTOR = '#ctl00_cphLeftColumn_ctl00_btnGive';
        const PRICE_INPUT_SELECTOR = '#ctl00_cphLeftColumn_ctl00_txtPriceTag';
        const ITEM_DROPDOWN_SELECTOR = '#ctl00_cphLeftColumn_ctl00_ddlItem';
        const FORM_CONTENT_DIV_SELECTOR = '#ctl00_cphLeftColumn_ctl00_updMain';
        const BASE_DELAY_MS = 2000;
        const POST_PRICE_SET_DELAY_MS = 100;
        const STORAGE_KEY_ITEMS_OFFER = 'popmundo_offerItem_items_swqp';
        const STORAGE_KEY_RUNNING_OFFER = 'popmundo_offerItem_running_swqp';
        const STORAGE_KEY_PRICE_OFFER = 'popmundo_offerItem_targetPrice';

        // *** NOVA FUNÇÃO: Remover a caixa de aviso ***
        function removeWarningBox() {
            const warningBox = Array.from(document.querySelectorAll('.box h2')).find(h2 => h2.textContent.trim() === "Quem avisa amigo é!");
            if (warningBox && warningBox.parentElement) {
                warningBox.parentElement.remove();
                console.log("Bulk Helper: Caixa de aviso 'Quem avisa amigo é!' removida.");
            }
        }

        function createOfferUI() {
            if (document.getElementById('bulkOfferUIScript')) return;

            const mainBoxWithForm = document.querySelector(FORM_CONTENT_DIV_SELECTOR)?.closest('.box');
            if (!mainBoxWithForm) {
                console.error("Bulk Helper: Não foi possível encontrar a caixa principal do formulário.");
                return;
            }

            const nativeTitles = mainBoxWithForm.querySelectorAll('h2, h3');
            nativeTitles.forEach(title => {
                if (title.textContent.includes('Ofertar um item') || title.textContent.includes('Selecione um item para ofertar')) {
                    title.remove();
                }
            });

            const scriptUIArea = document.createElement('div');
            scriptUIArea.id = 'bulkOfferUIScript';
            scriptUIArea.className = 'bulk-helper-wrapper';
            scriptUIArea.innerHTML = `
                <div class="panel-header">
                    <h2><i class="fa-solid fa-dolly"></i>Bulk Offer Helper</h2>
                </div>
                <div class="automation-panel-compact">
                    <div class="config-container">
                        <div class="config-item">
                            <label for="itemNameInputScript">Nome do Item:</label>
                            <input type="text" id="itemNameInputScript" placeholder="Ex: Analgésicos">
                        </div>
                        <div class="config-item">
                            <label for="itemQuantityInputScript">Quantidade:</label>
                            <input type="number" id="itemQuantityInputScript" min="1" value="1">
                        </div>
                         <div class="config-item config-item-full">
                            <label for="itemPriceInputScript">Preço (M$):</label>
                            <input type="number" id="itemPriceInputScript" min="0" step="1" value="0">
                        </div>
                    </div>
                    <div class="action-buttons">
                        <button id="startOfferByNameQtyPriceBtnScript" type="button" class="btn-start"><i class="fa-solid fa-play"></i> Ofertar</button>
                        <button id="stopBulkOfferBtnScript" type="button" class="btn-stop"><i class="fa-solid fa-stop"></i> Parar</button>
                    </div>
                    <div id="bulkOfferStatusScript" class="status-display">Status: Pronto.</div>
                </div>
            `;
            mainBoxWithForm.insertBefore(scriptUIArea, mainBoxWithForm.firstChild);
            document.getElementById('startOfferByNameQtyPriceBtnScript').addEventListener('click', startOfferByNameQuantityPrice);
            document.getElementById('stopBulkOfferBtnScript').addEventListener('click', stopOffer);
            addGlobalStyles();
        }

        async function startOfferByNameQuantityPrice() {
            const itemNameInput = document.getElementById('itemNameInputScript');
            const quantityInput = document.getElementById('itemQuantityInputScript');
            const priceInput = document.getElementById('itemPriceInputScript');
            const statusDiv = document.getElementById('bulkOfferStatusScript');
            const inputText = itemNameInput.value.trim();
            const requestedQuantity = parseInt(quantityInput.value, 10);
            const requestedPrice = parseInt(priceInput.value, 10);
            if (!inputText) { statusDiv.textContent = "Erro: Digite o início do nome do item."; return; }
            if (isNaN(requestedQuantity) || requestedQuantity < 1) { statusDiv.textContent = "Erro: Quantidade inválida."; return; }
            if (isNaN(requestedPrice) || requestedPrice < 0) { statusDiv.textContent = "Erro: Preço inválido."; return; }
            const allItemsFound = Array.from(document.querySelector(ITEM_DROPDOWN_SELECTOR).options)
                .filter(option => option.value && option.value !== "-1" && option.textContent.trim().toLowerCase().startsWith(inputText.toLowerCase()))
                .map(option => ({ value: option.value, text: option.textContent.trim() }));
            if (allItemsFound.length === 0) {
                statusDiv.textContent = `Status: Nenhum item encontrado começando com "${inputText}".`;
                return;
            }
            const itemsToOfferThisRun = allItemsFound.slice(0, requestedQuantity);
            statusDiv.textContent = `Encontrado(s) ${allItemsFound.length}. Ofertando ${itemsToOfferThisRun.length} por ${requestedPrice} M$...`;
            await GM_setValue(STORAGE_KEY_PRICE_OFFER, requestedPrice);
            await GM_setValue(STORAGE_KEY_ITEMS_OFFER, JSON.stringify(itemsToOfferThisRun));
            await GM_setValue(STORAGE_KEY_RUNNING_OFFER, true);
            disableOfferButtons(true);
            await processNextOffer();
        }
        async function stopOffer() {
            await GM_deleteValue(STORAGE_KEY_ITEMS_OFFER);
            await GM_deleteValue(STORAGE_KEY_RUNNING_OFFER);
            await GM_deleteValue(STORAGE_KEY_PRICE_OFFER);
            const statusDiv = document.getElementById('bulkOfferStatusScript');
            if (statusDiv) statusDiv.textContent = "Status: Oferta interrompida pelo usuário.";
            disableOfferButtons(false);
        }
        function disableOfferButtons(disabled) {
             document.getElementById('startOfferByNameQtyPriceBtnScript').disabled = disabled;
             document.getElementById('stopBulkOfferBtnScript').disabled = !disabled;
             document.getElementById('itemNameInputScript').disabled = disabled;
             document.getElementById('itemQuantityInputScript').disabled = disabled;
             document.getElementById('itemPriceInputScript').disabled = disabled;
        }
        async function processNextOffer() {
            const isRunning = await GM_getValue(STORAGE_KEY_RUNNING_OFFER, false);
            if (!isRunning) { disableOfferButtons(false); return; }
            let itemsToOffer = JSON.parse(await GM_getValue(STORAGE_KEY_ITEMS_OFFER, '[]'));
            const statusDiv = document.getElementById('bulkOfferStatusScript');
            if (itemsToOffer.length === 0) {
                statusDiv.textContent = "Status: Todas as ofertas foram concluídas!";
                await stopOffer();
                return;
            }
            const itemDropdown = document.querySelector(ITEM_DROPDOWN_SELECTOR);
            const offerButton = document.querySelector(OFFER_BUTTON_SELECTOR);
            const pagePriceInput = document.querySelector(PRICE_INPUT_SELECTOR);
            if (!itemDropdown || !offerButton) {
                statusDiv.textContent = "Erro Crítico: Elementos da página desapareceram.";
                await stopOffer(); return;
            }
            const itemToOffer = itemsToOffer.shift();
            const targetPrice = await GM_getValue(STORAGE_KEY_PRICE_OFFER, 0);
            if (pagePriceInput) pagePriceInput.value = String(targetPrice);
            await new Promise(resolve => setTimeout(resolve, POST_PRICE_SET_DELAY_MS));
            const initialTotalCount = JSON.parse(await GM_getValue(STORAGE_KEY_ITEMS_OFFER, '[]')).length + itemsToOffer.length + 1;
            statusDiv.textContent = `Ofertando ${initialTotalCount - itemsToOffer.length}/${initialTotalCount}: '${itemToOffer.text}'...`;
            itemDropdown.value = itemToOffer.value;
            if (itemDropdown.value !== itemToOffer.value) {
                 statusDiv.textContent = `Erro: Falha ao selecionar '${itemToOffer.text}'. Pulando...`;
                 await GM_setValue(STORAGE_KEY_ITEMS_OFFER, JSON.stringify(itemsToOffer));
                 setTimeout(processNextOffer, BASE_DELAY_MS / 2); return;
            }
            await GM_setValue(STORAGE_KEY_ITEMS_OFFER, JSON.stringify(itemsToOffer));
            await new Promise(resolve => setTimeout(resolve, BASE_DELAY_MS));
            if (!await GM_getValue(STORAGE_KEY_RUNNING_OFFER, false)) { disableOfferButtons(false); return; }
            offerButton.click();
        }
        async function checkOfferStateOnLoad() {
            removeWarningBox(); // Chamar a nova função
            createOfferUI();
            const isRunning = await GM_getValue(STORAGE_KEY_RUNNING_OFFER, false);
            if (isRunning) {
                disableOfferButtons(true);
                document.getElementById('bulkOfferStatusScript').textContent = "Status: Recarregado, continuando oferta...";
                await new Promise(resolve => setTimeout(resolve, 500));
                await processNextOffer();
            } else {
                disableOfferButtons(false);
            }
        }
        checkOfferStateOnLoad();
    }

    // =================================================================================
    // --- FUNCIONALIDADE 2: ACEITAR OFERTAS EM MASSA ---
    // =================================================================================
    function setupAcceptPage() {
        const BASE_DELAY_MS = 2000;
        const STORAGE_KEY_RUNNING_ACCEPT = 'popmundo_acceptItem_running';
        const STORAGE_KEY_MAX_PRICE_ACCEPT = 'popmundo_acceptItem_maxPrice';
        const STORAGE_KEY_ITEM_NAME_ACCEPT = 'popmundo_acceptItem_itemName';
        const STORAGE_KEY_ACCEPTED_COUNT = 'popmundo_acceptItem_accepted_count';
        const STORAGE_KEY_TOTAL_SPENT_ACCEPT = 'popmundo_acceptItem_totalSpent';

        function createAcceptUI() {
            if (document.getElementById('bulkAcceptUIScript')) return;
            const offersSection = Array.from(document.querySelectorAll('.box'))
                .find(box => box.textContent.includes('Itens sendo ofertados a você'));
            if (!offersSection) {
                console.log("Bulk Accept Helper: Seção 'Itens sendo ofertados a você' não encontrada.");
                return;
            }
            const scriptUIArea = document.createElement('div');
            scriptUIArea.id = 'bulkAcceptUIScript';
            scriptUIArea.className = 'bulk-helper-wrapper';
            scriptUIArea.innerHTML = `
                 <div class="panel-header">
                    <h2><i class="fa-solid fa-check-circle"></i>Bulk Accept Helper</h2>
                </div>
                <div class="automation-panel-compact">
                    <div class="config-container">
                        <div class="config-item">
                            <label for="itemNameInputAcceptScript">Nome do Item (Opcional):</label>
                            <input type="text" id="itemNameInputAcceptScript" placeholder="Deixe em branco para todos">
                        </div>
                        <div class="config-item">
                            <label for="maxPriceInputScript">Preço MÁXIMO (M$):</label>
                            <input type="number" id="maxPriceInputScript" min="0" step="1" value="55000">
                        </div>
                    </div>
                    <div class="action-buttons">
                        <button id="startAcceptBtnScript" type="button" class="btn-start"><i class="fa-solid fa-play"></i> Aceitar</button>
                        <button id="stopAcceptBtnScript" type="button" class="btn-stop"><i class="fa-solid fa-stop"></i> Parar</button>
                    </div>
                    <div id="bulkAcceptStatusScript" class="status-display">Status: Pronto.</div>
                    <div id="bulkAcceptSpentScript" class="spent-display">Gasto Total: 0 M$</div>
                </div>
            `;
            offersSection.insertBefore(scriptUIArea, offersSection.firstChild);
            document.getElementById('startAcceptBtnScript').addEventListener('click', startBulkAccept);
            document.getElementById('stopAcceptBtnScript').addEventListener('click', stopBulkAccept);
            addGlobalStyles();
        }

        async function startBulkAccept() {
            const priceInput = document.getElementById('maxPriceInputScript');
            const nameInput = document.getElementById('itemNameInputAcceptScript');
            const statusDiv = document.getElementById('bulkAcceptStatusScript');
            const maxPrice = parseInt(priceInput.value.replace(/[.,]/g, ''), 10);
            const targetName = nameInput.value.trim().toLowerCase();
            if (isNaN(maxPrice) || maxPrice < 0) {
                statusDiv.textContent = "Erro: Preço máximo inválido.";
                priceInput.focus();
                return;
            }
            statusDiv.textContent = `Iniciando... Buscando ofertas para "${targetName || 'qualquer item'}" com preço até ${maxPrice} M$.`;
            document.getElementById('bulkAcceptSpentScript').textContent = `Gasto Total: 0 M$`;
            await GM_setValue(STORAGE_KEY_MAX_PRICE_ACCEPT, maxPrice);
            await GM_setValue(STORAGE_KEY_ITEM_NAME_ACCEPT, targetName);
            await GM_setValue(STORAGE_KEY_RUNNING_ACCEPT, true);
            await GM_setValue(STORAGE_KEY_ACCEPTED_COUNT, 0);
            await GM_setValue(STORAGE_KEY_TOTAL_SPENT_ACCEPT, 0);
            disableAcceptButtons(true);
            await processNextAccept();
        }

        async function stopBulkAccept() {
            const totalSpent = await GM_getValue(STORAGE_KEY_TOTAL_SPENT_ACCEPT, 0);
            const acceptedCount = await GM_getValue(STORAGE_KEY_ACCEPTED_COUNT, 0);
            await GM_deleteValue(STORAGE_KEY_RUNNING_ACCEPT);
            await GM_deleteValue(STORAGE_KEY_MAX_PRICE_ACCEPT);
            await GM_deleteValue(STORAGE_KEY_ITEM_NAME_ACCEPT);
            await GM_deleteValue(STORAGE_KEY_ACCEPTED_COUNT);
            await GM_deleteValue(STORAGE_KEY_TOTAL_SPENT_ACCEPT);
            const statusDiv = document.getElementById('bulkAcceptStatusScript');
            if (statusDiv) statusDiv.textContent = `Status: Interrompido. Total aceito: ${acceptedCount}. Gasto: ${totalSpent} M$.`;
            disableAcceptButtons(false);
        }

        function disableAcceptButtons(disabled) {
            document.getElementById('startAcceptBtnScript').disabled = disabled;
            document.getElementById('stopAcceptBtnScript').disabled = !disabled;
            document.getElementById('maxPriceInputScript').disabled = disabled;
            document.getElementById('itemNameInputAcceptScript').disabled = disabled;
        }

        function parseBrazilianCurrency(valueStr) {
            let cleanStr = valueStr.replace(/[^\d.,]/g, '');
            let parts = cleanStr.split(',');
            let integerPart = parts[0].replace(/\./g, '');
            return parseInt(integerPart, 10) || 0;
        }

        async function processNextAccept() {
            if (!await GM_getValue(STORAGE_KEY_RUNNING_ACCEPT, false)) {
                disableAcceptButtons(false);
                return;
            }
            const maxPrice = await GM_getValue(STORAGE_KEY_MAX_PRICE_ACCEPT, -1);
            const targetName = await GM_getValue(STORAGE_KEY_ITEM_NAME_ACCEPT, '');
            const acceptedCount = await GM_getValue(STORAGE_KEY_ACCEPTED_COUNT, 0);
            const totalSpent = await GM_getValue(STORAGE_KEY_TOTAL_SPENT_ACCEPT, 0);
            const statusDiv = document.getElementById('bulkAcceptStatusScript');
            const spentDiv = document.getElementById('bulkAcceptSpentScript');

            const offersSection = Array.from(document.querySelectorAll('.box'))
                .find(box => box.textContent.includes('Itens sendo ofertados a você'));
            if (!offersSection) {
                statusDiv.textContent = "Status: Seção de ofertas não encontrada. Concluindo.";
                await stopBulkAccept();
                return;
            }
            const offerParagraphs = Array.from(offersSection.querySelectorAll('p.nobmargin'))
                .filter(p => p.textContent.includes('Oferecido por') || p.textContent.includes('custo:'));

            if (offerParagraphs.length === 0) {
                statusDiv.textContent = `Status: Nenhuma oferta encontrada. Total aceito: ${acceptedCount}. Gasto: ${totalSpent} M$. Concluído!`;
                await stopBulkAccept();
                return;
            }

            let foundItemToAccept = false;
            for (const paragraph of offerParagraphs) {
                const itemLink = paragraph.querySelector('a[id*="lnkItem"]');
                const itemName = itemLink ? itemLink.textContent.trim() : '';
                if (!itemName) continue;

                let itemPrice = 0;
                let priceText = "Presente";
                const costMatch = paragraph.textContent.match(/custo:\s*([\d.,]+)\s*M\$/);
                if (costMatch && costMatch[1]) {
                    itemPrice = parseBrazilianCurrency(costMatch[1]);
                    priceText = `${itemPrice} M$`;
                }

                const isNameOk = (targetName === '' || itemName.toLowerCase().includes(targetName));
                const isPriceOk = (itemPrice <= maxPrice);

                if (isNameOk && isPriceOk) {
                    const newCount = acceptedCount + 1;
                    const newTotalSpent = totalSpent + itemPrice;
                    await GM_setValue(STORAGE_KEY_ACCEPTED_COUNT, newCount);
                    await GM_setValue(STORAGE_KEY_TOTAL_SPENT_ACCEPT, newTotalSpent);

                    statusDiv.textContent = `Aceitando #${newCount}: '${itemName}' (${priceText})...`;
                    spentDiv.textContent = `Gasto Total: ${newTotalSpent} M$`;
                    foundItemToAccept = true;

                    let acceptButton = paragraph.querySelector('input[value="Comprar e pagar pela entrega"]') ||
                                       paragraph.querySelector('input[id*="btnAccept"]') ||
                                       paragraph.querySelector('input[name*="btnAccept"]') ||
                                       paragraph.querySelector('input[type="submit"]:not([value="Rejeitar"])');

                    if (!acceptButton) {
                        console.log("Botão de aceitar não encontrado para este item");
                        continue;
                    }

                    await new Promise(resolve => setTimeout(resolve, BASE_DELAY_MS));
                    if (!await GM_getValue(STORAGE_KEY_RUNNING_ACCEPT, false)) {
                        console.log("Processo interrompido durante o delay final.");
                        disableAcceptButtons(false);
                        return;
                    }
                    acceptButton.click();
                    break;
                }
            }

            if (!foundItemToAccept) {
                statusDiv.textContent = `Status: Nenhuma outra oferta corresponde. Total aceito: ${acceptedCount}. Gasto: ${totalSpent} M$. Concluído!`;
                await stopBulkAccept();
            }
        }

        async function checkAcceptStateOnLoad() {
            createAcceptUI();
            if (await GM_getValue(STORAGE_KEY_RUNNING_ACCEPT, false)) {
                disableAcceptButtons(true);
                const acceptedCount = await GM_getValue(STORAGE_KEY_ACCEPTED_COUNT, 0);
                const totalSpent = await GM_getValue(STORAGE_KEY_TOTAL_SPENT_ACCEPT, 0);
                document.getElementById('bulkAcceptStatusScript').textContent = `Status: Recarregado, continuando... Total aceito: ${acceptedCount}`;
                document.getElementById('bulkAcceptSpentScript').textContent = `Gasto Total: ${totalSpent} M$`;
                await new Promise(resolve => setTimeout(resolve, 500));
                await processNextAccept();
            } else {
                disableAcceptButtons(false);
            }
        }
        checkAcceptStateOnLoad();
    }

    // =================================================================================
    // --- ESTILOS GLOBAIS PARA A UI ---
    // =================================================================================
    function addGlobalStyles() {
        const fontAwesomeLink = document.createElement('link');
        fontAwesomeLink.rel = 'stylesheet';
        fontAwesomeLink.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css';
        document.head.appendChild(fontAwesomeLink);

        GM_addStyle(`
            .bulk-helper-wrapper {
                margin-bottom: 20px;
            }
            .panel-header {
                border-bottom: 1px solid #EEE;
                padding-bottom: 4px;
                margin-bottom: 10px;
            }
            .panel-header h2 {
                font-size: 1em;
                font-weight: normal;
                margin: 0;
                color: #000;
                display: flex;
                align-items: center;
            }
            .panel-header h2 i {
                margin-right: 8px;
                color: #555;
            }
            .automation-panel-compact {
                background-color: #f0f0f0;
                border: 1px solid #dcdcdc;
                border-radius: 6px;
                padding: 12px;
                box-shadow: 0 1px 3px rgba(0,0,0,0.08);
                font-family: Arial, sans-serif;
                font-size: 13px;
            }
            .config-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; margin-bottom: 12px; }
            .config-item-full { grid-column: 1 / -1; }
            .config-item label { display: block; font-weight: bold; margin-bottom: 4px; font-size: 11px; color: #555; }
            .config-item input[type="number"], .config-item input[type="text"] { width: 100%; padding: 6px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; }
            .action-buttons { display: flex; gap: 8px; margin-bottom: 10px; }
            .action-buttons button { display: inline-flex; align-items: center; justify-content: center; flex-grow: 1; padding: 6px 12px; border: 1px solid #555; border-radius: 4px; font-weight: bold; font-size: 12px; cursor: pointer; transition: all 0.2s; color: #333; text-shadow: 1px 1px 1px #fff; }
            .action-buttons button:hover:not(:disabled) { border-color: #333; }
            .action-buttons button:disabled { background: #e9ecef !important; border-color: #ccc !important; color: #999 !important; cursor: not-allowed; opacity: 0.7; }
            .action-buttons button i { margin-right: 6px; }
            .btn-start { background: linear-gradient(to bottom, #d4edda, #c3e6cb); border-color: #28a745; }
            .btn-start:hover:not(:disabled) { background: linear-gradient(to bottom, #c3e6cb, #b1dfbb); }
            .btn-stop { background: linear-gradient(to bottom, #f8d7da, #f5c6cb); border-color: #dc3545; }
            .btn-stop:hover:not(:disabled) { background: linear-gradient(to bottom, #f5c6cb, #f1b0b7); }
            .status-display { font-size: 12px; text-align: center; background-color: #e9ecef; padding: 6px; border-radius: 4px; margin-bottom: 5px; font-weight: 500; color: #495057; }
            .spent-display { font-size: 12px; text-align: center; background-color: #d1fae5; padding: 6px; border-radius: 4px; font-weight: 500; color: #065f46; }
        `);
    }

    // Inicia o script
    initializeScript();
})();