Bazaar Item Search powered by IronNerd

View items you are searching for in bazaars!

// ==UserScript==
// @name         Bazaar Item Search powered by IronNerd
// @namespace    [email protected]
// @version      0.4.5
// @description  View items you are searching for in bazaars!
// @author       Nurv [669537]
// @match        https://www.torn.com/page.php?sid=ItemMarket*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-end
// @license      Copyright IronNerd.me
// @connect      ironnerd.me
// ==/UserScript==

(function () {
    'use strict';

    console.log('IronNerd Bazaar Enhancements script started.');

    // ------------------ Configuration ------------------
    const BACKEND_URL = 'https://www.ironnerd.me';
    const ongoingRequests = new Set();
    let currentPage = 1;
    const itemsPerPage = 15;
    let allBazaarItems = [];

    // ------------------ Initialization ------------------
    init();

    function init() {
        injectAdditionalStyles();
        ensureBazaarEnhancerContainer();
        addBazaarButtons();
        observeDOMChanges();
        detectSearch();
        observeDarkMode();
        initializeTopCheapestItems();
        adjustBazaarEnhancerContainerTheme();
    }

    // ------------------ Utility Functions ------------------

    function debounce(func, wait) {
        let timeout;
        return function (...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(this, args), wait);
        };
    }

    function getItemInfoFromURL() {
        const url = new URL(window.location.href);
        let itemID = null;
        let itemName = '';

        let hash = url.hash.startsWith('#/') ? url.hash.substring(2) : url.hash.substring(1);
        const hashParts = hash.split('/');
        const paramsString = hashParts[hashParts.length - 1];
        const hashParams = new URLSearchParams(paramsString);
        itemID = hashParams.get('itemID');
        itemName = hashParams.get('itemName') ? decodeURIComponent(hashParams.get('itemName')) : '';

        if (!itemID) {
            const searchParams = url.searchParams;
            itemID = searchParams.get('itemID');
            itemName = searchParams.get('itemName') ? decodeURIComponent(searchParams.get('itemName')) : '';
        }

        if (itemID) {
            return { itemID: parseInt(itemID), itemName };
        }

        return { itemID: null, itemName: '' };
    }

    function ensureBazaarEnhancerContainer() {
        let container = document.getElementById('bazaar-enhancer-container');
        if (!container) {
            container = document.createElement('div');
            container.id = 'bazaar-enhancer-container';

            const delimiter = document.querySelector('.delimiter___zFh2E');
            if (delimiter && delimiter.parentNode) {
                delimiter.parentNode.insertBefore(container, delimiter.nextSibling);
            } else {
                document.body.appendChild(container);
            }

            console.log('IronNerd Bazaar Enhancements: `bazaar-enhancer-container` created and appended to the DOM.');
        } else {
            console.log('IronNerd Bazaar Enhancements: `bazaar-enhancer-container` already exists.');
        }
    }

    function addBazaarButtons() {
        const addListingsLink = document.querySelector('a[href="#/addListing"]');
        if (addListingsLink) {
            const linksContainer = addListingsLink.parentElement;
            if (linksContainer && !document.getElementById('bazaarButton')) {
                const bazaarLink = addListingsLink.cloneNode(true);
                bazaarLink.id = 'bazaarButton';
                bazaarLink.setAttribute('aria-labelledby', 'Bazaar');
                bazaarLink.href = '#';

                const linkTitle = bazaarLink.querySelector('.linkTitle____NPyM');
                if (linkTitle) {
                    linkTitle.innerText = 'Bazaar';
                }

                const svgIcon = bazaarLink.querySelector('svg');
                if (svgIcon) {
                    svgIcon.innerHTML = '<svg fill="#000000" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 902.86 902.86" xml:space="preserve"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <g> <path d="M671.504,577.829l110.485-432.609H902.86v-68H729.174L703.128,179.2L0,178.697l74.753,399.129h596.751V577.829z M685.766,247.188l-67.077,262.64H131.199L81.928,246.756L685.766,247.188z"></path> <path d="M578.418,825.641c59.961,0,108.743-48.783,108.743-108.744s-48.782-108.742-108.743-108.742H168.717 c-59.961,0-108.744,48.781-108.744,108.742s48.782,108.744,108.744,108.744c59.962,0,108.743-48.783,108.743-108.744 c0-14.4-2.821-28.152-7.927-40.742h208.069c-5.107,12.59-7.928,26.342-7.928,40.742 C469.675,776.858,518.457,825.641,578.418,825.641z M209.46,716.897c0,22.467-18.277,40.744-40.743,40.744 c-22.466,0-40.744-18.277-40.744-40.744c0-22.465,18.277-40.742,40.744-40.742C191.183,676.155,209.46,694.432,209.46,716.897z M619.162,716.897c0,22.467-18.277,40.744-40.743,40.744s-40.743-18.277-40.743-40.744c0-22.465,18.277-40.742,40.743-40.742 S619.162,694.432,619.162,716.897z"></path> </g> </g> </g></svg>';
                }

                bazaarLink.addEventListener('click', (e) => {
                    e.preventDefault();
                    openShowBazaarModal();
                });

                linksContainer.appendChild(bazaarLink);

                console.log('Bazaar button added to layout.');
            }
        }
    }

    function createBazaarButton(id, text) {
        const button = document.createElement('button');
        button.id = id;
        button.innerText = text;
        button.style.cursor = 'pointer';
        button.style.padding = '6px 10px';
        button.style.margin = '5px';
        button.style.backgroundColor = '#4caf50';
        button.style.color = '#fff';
        button.style.border = 'none';
        button.style.borderRadius = '4px';
        button.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.2)';
        button.style.fontSize = '12px';

        button.type = 'button';

        button.addEventListener('click', () => {
            console.log(`${text} button clicked!`);
            openShowBazaarModal();
        });

        return button;
    }

    function observeDOMChanges() {
        const targetNode = document.body;
        const config = { childList: true, subtree: true };

        const debouncedAddButtons = debounce(() => {
            addBazaarButtons();
        }, 500);

        const callback = function (mutationsList, observer) {
            for (let mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    debouncedAddButtons();
                }
            }
        };

        const observer = new MutationObserver(callback);
        observer.observe(targetNode, config);
    }

    function openShowBazaarModal() {

        createShowBazaarModal();

        const modal = document.getElementById('showBazaarModal');
        if (modal) {
            modal.style.display = 'flex';

            const { itemID, itemName } = getItemInfoFromURL();
            const itemNameDisplay = modal.querySelector('#itemNameDisplay');
            const resultsContainer = modal.querySelector('#showBazaarResults');

            currentPage = 1;
            allBazaarItems = [];

            if (itemName && itemNameDisplay) {
                itemNameDisplay.innerText = `Showing Bazaar Listings for: ${itemName}`;
            } else {
                itemNameDisplay.innerText = 'No item selected.';
            }

            if (itemID) {
                fetchBazaarItems(itemID);
            } else {
                resultsContainer.innerHTML = '<p>No item selected for display.</p>';
            }

            trapFocus(modal);
        } else {
            console.error('IronNerd Bazaar Enhancements: showBazaarModal element not found.');
        }
    }

    function createShowBazaarModal() {
        if (document.getElementById('showBazaarModal')) {
            return;
        }

        const overlay = document.createElement('div');
        overlay.id = 'showBazaarModal';
        overlay.setAttribute('role', 'dialog');
        overlay.setAttribute('aria-labelledby', 'modal-title');
        overlay.setAttribute('aria-modal', 'true');
        overlay.style.position = 'fixed';
        overlay.style.top = '0';
        overlay.style.left = '0';
        overlay.style.width = '100%';
        overlay.style.height = '100%';
        overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
        overlay.style.display = 'none';
        overlay.style.zIndex = '10000';
        overlay.style.overflowY = 'auto';
        overlay.style.alignItems = 'center';
        overlay.style.justifyContent = 'center';

        const modalContent = document.createElement('div');
        modalContent.id = 'modal-content';
        modalContent.style.backgroundColor = '#9e9b9b';
        modalContent.style.padding = '20px';
        modalContent.style.borderRadius = '8px';
        modalContent.style.width = '90%';
        modalContent.style.maxWidth = '800px';
        modalContent.style.position = 'relative';
        modalContent.style.boxShadow = '0 5px 15px rgba(0,0,0,0.3)';
        modalContent.style.maxHeight = '90%';
        modalContent.style.overflowY = 'auto';

        const closeBtn = document.createElement('span');
        closeBtn.innerHTML = '&times;';
        closeBtn.style.position = 'absolute';
        closeBtn.style.top = '10px';
        closeBtn.style.right = '20px';
        closeBtn.style.fontSize = '30px';
        closeBtn.style.fontWeight = 'bold';
        closeBtn.style.cursor = 'pointer';
        closeBtn.style.color = '#aaa';
        closeBtn.addEventListener('mouseover', () => {
            closeBtn.style.color = '#000';
        });
        closeBtn.addEventListener('mouseout', () => {
            closeBtn.style.color = '#aaa';
        });
        closeBtn.addEventListener('click', closeShowBazaarModal);

        const title = document.createElement('h2');
        title.id = 'modal-title';
        title.style.textAlign = 'center';
        title.style.marginBottom = '20px';

        const itemNameDisplay = document.createElement('h3');
        itemNameDisplay.id = 'itemNameDisplay';
        itemNameDisplay.style.textAlign = 'center';
        itemNameDisplay.style.marginBottom = '10px';
        itemNameDisplay.style.color = '#333';
        modalContent.appendChild(itemNameDisplay);

        const resultsContainer = document.createElement('div');
        resultsContainer.id = 'showBazaarResults';
        resultsContainer.style.marginTop = '20px';

        const statusDiv = document.createElement('div');
        statusDiv.id = 'showBazaarStatusMessage';
        statusDiv.style.marginTop = '10px';
        statusDiv.style.fontWeight = 'bold';

        modalContent.appendChild(closeBtn);
        modalContent.appendChild(title);
        modalContent.appendChild(resultsContainer);
        modalContent.appendChild(statusDiv);

        overlay.appendChild(modalContent);

        document.body.appendChild(overlay);

        overlay.addEventListener('click', function (event) {
            if (event.target === overlay) {
                closeShowBazaarModal();
            }
        });

        document.addEventListener('keydown', function (event) {
            if (event.key === 'Escape') {
                closeShowBazaarModal();
            }
        });

    }

    function closeShowBazaarModal() {
        const modal = document.getElementById('showBazaarModal');
        if (modal) {
            modal.style.display = 'none';
        }
    }

    function fetchBazaarItems(itemID) {
        const modal = document.getElementById('showBazaarModal');
        const resultsContainer = modal.querySelector('#showBazaarResults');
        const statusDiv = modal.querySelector('#showBazaarStatusMessage');

        if (ongoingRequests.has(`bazaar_items_${itemID}`)) {
            return;
        }


        ongoingRequests.add(`bazaar_items_${itemID}`);

        resultsContainer.innerHTML = `
            <p>Loading...</p>
            <div class="loading-spinner"></div>
        `;
        statusDiv.innerHTML = '';


        GM_xmlhttpRequest({
            method: 'GET',
            url: `${BACKEND_URL}/get_bazaar_items/${itemID}`,
            headers: {
                'Accept': 'application/json',

            },
            onload: function (response) {
                ongoingRequests.delete(`bazaar_items_${itemID}`);

                if (response.status === 200) {
                    try {
                        const data = JSON.parse(response.responseText);
                        if (data.bazaar_items) {
                            allBazaarItems = data.bazaar_items;
                            displayBazaarItems(allBazaarItems);
                        } else {
                            resultsContainer.innerHTML = '<p>No items found.</p>';
                        }
                    } catch (e) {
                        resultsContainer.innerHTML = '<p>Error parsing server response.</p>';
                    }
                } else {
                    resultsContainer.innerHTML = `<p>Error: ${response.status} - ${response.statusText}</p>`;
                }
            },
            onerror: function (error) {
                ongoingRequests.delete(`bazaar_items_${itemID}`);

                resultsContainer.innerHTML = '<p>Network error occurred. Please try again later.</p>';
            }
        });
    }

    function displayBazaarItems(items) {
        const modal = document.getElementById('showBazaarModal');
        const resultsContainer = modal.querySelector('#showBazaarResults');
        resultsContainer.innerHTML = '';

        if (items.length === 0) {
            resultsContainer.innerHTML = '<p>No items found in registered bazaars.</p>';
            return;
        }

        const totalPages = Math.ceil(items.length / itemsPerPage);
        if (currentPage > totalPages) currentPage = totalPages;

        const startIndex = (currentPage - 1) * itemsPerPage;
        const endIndex = Math.min(startIndex + itemsPerPage, items.length);
        const paginatedItems = items.slice(startIndex, endIndex);

        const tableContainer = document.createElement('div');
        tableContainer.style.overflowX = 'table-responsive';
        tableContainer.style.width = '100%';

        const table = document.createElement('table');
        table.className = 'bazaar-table';
        table.style.width = '100%';
        table.style.borderCollapse = 'collapse';

        const thead = document.createElement('thead');
        const headerRow = document.createElement('tr');

        const headers = ['Image', 'Owner', 'Price ($)', 'Quantity', 'Visit Bazaar'];
        headers.forEach(header => {
            const th = document.createElement('th');
            th.innerText = header;
            th.style.border = '1px solid #ccc';
            th.style.padding = '8px';
            th.style.backgroundColor = '#f2f2f2';
            th.style.textAlign = 'center';
            th.style.fontSize = '14px';
            headerRow.appendChild(th);
        });
        thead.appendChild(headerRow);
        table.appendChild(thead);

        const tbody = document.createElement('tbody');

        paginatedItems.forEach(item => {
            const tr = document.createElement('tr');

            const imgCell = document.createElement('td');
            imgCell.style.border = '1px solid #ccc';
            imgCell.style.padding = '4px';
            imgCell.style.textAlign = 'center';
            const img = document.createElement('img');
            img.src = `/images/items/${item.item_id}/small.png`;
            img.alt = item.name;
            img.style.height = '30px';
            imgCell.appendChild(img);
            tr.appendChild(imgCell);

            const ownerCell = document.createElement('td');
            ownerCell.setAttribute('data-label', 'Owner');
            ownerCell.style.border = '1px solid #ccc';
            ownerCell.style.padding = '6px';
            ownerCell.style.textAlign = 'center';
            ownerCell.style.fontSize = '14px';
            const ownerLink = document.createElement('a');
            ownerLink.href = `https://www.torn.com/profiles.php?XID=${item.user_id}`;
            ownerLink.textContent = item.user_id;
            ownerLink.target = '_blank';
            ownerLink.style.color = 'inherit';
            ownerLink.style.textDecoration = 'none';
            ownerLink.addEventListener('mouseover', () => {
                ownerLink.style.textDecoration = 'underline';
            });
            ownerLink.addEventListener('mouseout', () => {
                ownerLink.style.textDecoration = 'none';
            });
            ownerCell.appendChild(ownerLink);
            tr.appendChild(ownerCell);

            const priceTd = document.createElement('td');
            priceTd.innerText = `$${item.price.toLocaleString()}`;
            priceTd.setAttribute('data-label', 'Price ($)');
            priceTd.style.border = '1px solid #ccc';
            priceTd.style.padding = '6px';
            priceTd.style.textAlign = 'center';
            priceTd.style.fontSize = '14px';
            tr.appendChild(priceTd);

            const quantityTd = document.createElement('td');
            quantityTd.innerText = item.quantity;
            quantityTd.setAttribute('data-label', 'Quantity');
            quantityTd.style.border = '1px solid #ccc';
            quantityTd.style.padding = '6px';
            quantityTd.style.textAlign = 'center';
            quantityTd.style.fontSize = '14px';
            tr.appendChild(quantityTd);

            const bazaarTd = document.createElement('td');
            bazaarTd.style.border = '1px solid #ccc';
            bazaarTd.style.padding = '6px';
            bazaarTd.style.textAlign = 'center';
            bazaarTd.style.fontSize = '14px';
            const bazaarLink = document.createElement('a');
            bazaarLink.href = `https://www.torn.com/bazaar.php?userID=${item.user_id}`;
            bazaarLink.textContent = 'Visit';
            bazaarLink.target = '_blank';
            bazaarLink.style.color = '#007bff';
            bazaarLink.style.textDecoration = 'none';
            bazaarLink.addEventListener('mouseover', () => {
                bazaarLink.style.textDecoration = 'underline';
            });
            bazaarLink.addEventListener('mouseout', () => {
                bazaarLink.style.textDecoration = 'none';
            });
            bazaarTd.appendChild(bazaarLink);
            bazaarTd.setAttribute('data-label', 'Visit Bazaar');
            tr.appendChild(bazaarTd);

            tbody.appendChild(tr);
        });

        table.appendChild(tbody);
        tableContainer.appendChild(table);
        resultsContainer.appendChild(tableContainer);

        addPaginationControls(resultsContainer, allBazaarItems.length, totalPages);

        adjustBazaarTableTheme();
    }

    function addPaginationControls(container, totalItems, totalPages) {
        const existingPagination = container.querySelector('.pagination-controls');
        if (existingPagination) {
            existingPagination.remove();
        }

        if (totalPages <= 1) return;

        const paginationContainer = document.createElement('div');
        paginationContainer.className = 'pagination-controls';
        paginationContainer.style.display = 'flex';
        paginationContainer.style.justifyContent = 'center';
        paginationContainer.style.alignItems = 'center';
        paginationContainer.style.marginTop = '15px';
        paginationContainer.style.flexWrap = 'wrap';

        const prevButton = document.createElement('button');
        prevButton.innerText = 'Previous';
        prevButton.disabled = currentPage === 1;
        prevButton.className = 'pagination-button';
        prevButton.addEventListener('click', () => {
            if (currentPage > 1) {
                currentPage--;
                displayBazaarItems(allBazaarItems);
            }
        });
        paginationContainer.appendChild(prevButton);

        const pageIndicator = document.createElement('span');
        pageIndicator.innerText = `Page ${currentPage} of ${totalPages}`;
        pageIndicator.style.margin = '0 10px';
        pageIndicator.style.fontSize = '14px';
        paginationContainer.appendChild(pageIndicator);

        const nextButton = document.createElement('button');
        nextButton.innerText = 'Next';
        nextButton.disabled = currentPage === totalPages;
        nextButton.className = 'pagination-button';
        nextButton.addEventListener('click', () => {
            if (currentPage < totalPages) {
                currentPage++;
                displayBazaarItems(allBazaarItems);
            }
        });
        paginationContainer.appendChild(nextButton);

        container.appendChild(paginationContainer);
    }

    function fetchTopCheapestItems(itemID) {
        const { itemName } = getItemInfoFromURL();
        const container = document.getElementById('bazaar-enhancer-container');
        if (!container) {
            console.error('IronNerd Bazaar Enhancements: Container for top 3 items not found.');
            return;
        }

        if (ongoingRequests.has(`top_cheapest_${itemID}`)) {
            return;
        }

        ongoingRequests.add(`top_cheapest_${itemID}`);
        container.innerHTML = `
            <p>Loading top 3 cheapest items...</p>
            <div class="loading-spinner"></div>
        `;


        GM_xmlhttpRequest({
            method: 'GET',
            url: `${BACKEND_URL}/get_top_cheapest_items/${itemID}`,
            headers: {
                'Accept': 'application/json',
            },
            onload: function (response) {
                ongoingRequests.delete(`top_cheapest_${itemID}`);

                if (response.status === 200) {
                    try {
                        const data = JSON.parse(response.responseText);
                        if (data.top_cheapest_items && Array.isArray(data.top_cheapest_items)) {
                            displayTopCheapestItems(data.top_cheapest_items, itemName);
                        } else {
                            displayShowBazaarStatusMessage('error', 'Invalid data format received.');
                        }
                    } catch (e) {
                        container.innerHTML = '<p>Error parsing server response.</p>';
                        console.error('IronNerd Bazaar Enhancements: Parsing Error:', e);
                    }
                } else {
                    container.innerHTML = `<p>Error: ${response.status} - ${response.statusText}</p>`;
                    console.error('IronNerd Bazaar Enhancements: Fetch Top 3 Cheapest Items Error:', response.responseText);
                }
            },
            onerror: function (error) {
                ongoingRequests.delete(`top_cheapest_${itemID}`);

                container.innerHTML = '<p>Network error occurred. Please try again later.</p>';
                console.error('IronNerd Bazaar Enhancements: Network Error:', error);
            }
        });
    }

    function displayTopCheapestItems(items, itemName = 'Item') {
        const container = document.getElementById('bazaar-enhancer-container');
        container.innerHTML = '';

        if (!items || items.length === 0) {
            container.innerHTML = '<p>No items found.</p>';
            return;
        }

        const title = document.createElement('h3');
        title.innerText = `Top 3 Cheapest ${itemName} Bazaar Items`;
        title.style.textAlign = 'center';
        title.style.marginTop = '2px';
        title.style.marginBottom = '10px';
        container.appendChild(title);

        const tableContainer = document.createElement('div');
        tableContainer.style.overflowX = 'table-responsive';
        tableContainer.style.width = '100%';

        const table = document.createElement('table');
        table.className = 'top-cheapest-table';
        table.style.width = '100%';
        table.style.borderCollapse = 'collapse';

        const thead = document.createElement('thead');
        const headerRow = document.createElement('tr');

        const headers = ['Rank', 'Price ($)', 'Quantity', 'Seller', 'Visit Bazaar'];
        headers.forEach(headerText => {
            const th = document.createElement('th');
            th.innerText = headerText;
            th.style.border = '1px solid #ccc';
            th.style.padding = '8px';
            th.style.backgroundColor = '#e0e0e0';
            th.style.textAlign = 'center';
            th.style.fontSize = '14px';
            headerRow.appendChild(th);
        });
        thead.appendChild(headerRow);
        table.appendChild(thead);

        const tbody = document.createElement('tbody');

        items.forEach((item, index) => {
            const tr = document.createElement('tr');

            const rankTd = document.createElement('td');
            rankTd.innerText = index + 1;
            rankTd.style.border = '1px solid #ccc';
            rankTd.style.padding = '6px';
            rankTd.style.textAlign = 'center';
            rankTd.style.fontSize = '14px';
            tr.appendChild(rankTd);

            const priceTd = document.createElement('td');
            priceTd.innerText = `$${item.price.toLocaleString()}`;
            priceTd.setAttribute('data-label', 'Price ($)');
            priceTd.style.border = '1px solid #ccc';
            priceTd.style.padding = '6px';
            priceTd.style.textAlign = 'center';
            priceTd.style.fontSize = '14px';
            tr.appendChild(priceTd);

            const quantityTd = document.createElement('td');
            quantityTd.innerText = item.quantity;
            quantityTd.setAttribute('data-label', 'Quantity');
            quantityTd.style.border = '1px solid #ccc';
            quantityTd.style.padding = '6px';
            quantityTd.style.textAlign = 'center';
            quantityTd.style.fontSize = '14px';
            tr.appendChild(quantityTd);

            const sellerTd = document.createElement('td');
            sellerTd.setAttribute('data-label', 'Seller');
            sellerTd.style.border = '1px solid #ccc';
            sellerTd.style.padding = '6px';
            sellerTd.style.textAlign = 'center';
            sellerTd.style.fontSize = '14px';
            const sellerLink = document.createElement('a');
            sellerLink.href = `https://www.torn.com/profiles.php?XID=${item.user_id}`;
            sellerLink.textContent = item.user_id;
            sellerLink.target = '_blank';
            sellerLink.style.color = 'inherit';
            sellerLink.style.textDecoration = 'none';
            sellerLink.addEventListener('mouseover', () => {
                sellerLink.style.textDecoration = 'underline';
            });
            sellerLink.addEventListener('mouseout', () => {
                sellerLink.style.textDecoration = 'none';
            });
            sellerTd.appendChild(sellerLink);
            tr.appendChild(sellerTd);

            const bazaarTd = document.createElement('td');
            bazaarTd.style.border = '1px solid #ccc';
            bazaarTd.style.padding = '6px';
            bazaarTd.style.textAlign = 'center';
            bazaarTd.style.fontSize = '14px';
            const bazaarLink = document.createElement('a');
            bazaarLink.href = `https://www.torn.com/bazaar.php?userID=${item.user_id}`;
            bazaarLink.textContent = 'Visit';
            bazaarLink.target = '_blank';
            bazaarLink.style.color = '#007bff';
            bazaarLink.style.textDecoration = 'none';
            bazaarLink.addEventListener('mouseover', () => {
                bazaarLink.style.textDecoration = 'underline';
            });
            bazaarLink.addEventListener('mouseout', () => {
                bazaarLink.style.textDecoration = 'none';
            });
            bazaarTd.appendChild(bazaarLink);
            bazaarTd.setAttribute('data-label', 'Visit Bazaar');
            tr.appendChild(bazaarTd);

            tbody.appendChild(tr);
        });

        table.appendChild(tbody);
        tableContainer.appendChild(table);
        container.appendChild(tableContainer);

        adjustTopCheapestTableTheme();
    }

    function detectSearch() {
        window.addEventListener('hashchange', onHashChange, false);
        window.addEventListener('popstate', onHashChange, false);
        onHashChange();
    }

    function onHashChange() {
        const { itemID, itemName } = getItemInfoFromURL();
        if (itemID) {
            fetchTopCheapestItems(itemID);
        }
    }

    function initializeTopCheapestItems() {
        const { itemID, itemName } = getItemInfoFromURL();
        if (itemID) {
            fetchTopCheapestItems(itemID);
        } else {
            console.warn('IronNerd Bazaar Enhancements: Item ID not found in URL. Top 3 Cheapest Items will not be displayed.');
        }
    }


    function displayShowBazaarStatusMessage(status, message) {
        const statusDiv = document.getElementById('showBazaarStatusMessage');
        if (!statusDiv) return;

        statusDiv.innerHTML = '';

        const icon = document.createElement('span');
        icon.style.marginRight = '8px';
        if (status === 'success') {
            icon.textContent = '✅';
            statusDiv.style.color = '#155724';
            statusDiv.style.backgroundColor = '#d4edda';
        } else if (status === 'error') {
            icon.textContent = '❌';
            statusDiv.style.color = '#721c24';
            statusDiv.style.backgroundColor = '#f8d7da';
        } else if (status === 'info') {
            icon.textContent = 'ℹ️';
            statusDiv.style.color = '#004085';
            statusDiv.style.backgroundColor = '#cce5ff';
        }

        const messageSpan = document.createElement('span');
        messageSpan.textContent = message;

        statusDiv.appendChild(icon);
        statusDiv.appendChild(messageSpan);

        statusDiv.style.padding = '5px';
        statusDiv.style.borderRadius = '3px';
        statusDiv.style.display = 'flex';
        statusDiv.style.alignItems = 'center';
        statusDiv.style.transition = 'background-color 0.3s, color 0.3s';

        setTimeout(() => {
            statusDiv.textContent = '';
            statusDiv.style.display = 'none';
        }, 5000);
    }

    function trapFocus(modal) {
        const focusableElements = modal.querySelectorAll('a[href], button, textarea, input, select');
        if (focusableElements.length === 0) return;
        const firstFocusable = focusableElements[0];
        const lastFocusable = focusableElements[focusableElements.length - 1];

        modal.addEventListener('keydown', function (e) {
            const isTabPressed = (e.key === 'Tab' || e.keyCode === 9);

            if (!isTabPressed) return;

            if (e.shiftKey) {
                if (document.activeElement === firstFocusable) {
                    lastFocusable.focus();
                    e.preventDefault();
                }
            } else {
                if (document.activeElement === lastFocusable) {
                    firstFocusable.focus();
                    e.preventDefault();
                }
            }
        });
    }


    function injectAdditionalStyles() {
        const style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = `
    @keyframes spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
    }

    #showBazaarModal {
        background-color: rgba(0, 0, 0, 0.7);
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 10000;
        padding: 20px;
    }

    #showBazaarModal #modal-content {
        background-color: #fff;
        color: #000;
        padding: 20px;
        border-radius: 12px;
        max-width: 800px;
        width: 100%;
        box-sizing: border-box;
        box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
        overflow-y: auto;
        max-height: 80vh;
        margin: 0 10px;
    }

    #showBazaarModal h2 {
        text-align: center;
        font-size: 1.5em;
        margin-bottom: 15px;
        color: #333;
    }

    #itemNameDisplay {
        text-align: center;
        margin-bottom: 15px;
        color: #333;
        font-size: 1.3em;
        font-weight: bold;
    }

    #bazaar-enhancer-container {
        background-color: #ffffff;
        color: #000000;
        border: 1px solid #ddd;
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        border-radius: 8px;
        padding: 10px;
        margin: 10px 0;
        transition: background-color 0.3s, color 0.3s;
    }

    .dark-mode #bazaar-enhancer-container {
        background-color: rgba(0, 0, 0, 0.6);
        color: #f0f0f0;
        border: 1px solid rgba(255, 255, 255, 0.1);
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
    }

    #showBazaarModal table.bazaar-table,
    #bazaar-enhancer-container table.top-cheapest-table {
        color: black;
        width: 100%;
        border-collapse: collapse;
        margin-top: 10px;
        table-layout: auto;
    }

    #showBazaarModal table.bazaar-table th,
    #showBazaarModal table.bazaar-table td,
    #bazaar-enhancer-container table.top-cheapest-table th,
    #bazaar-enhancer-container table.top-cheapest-table td {
        text-align: center;
        padding: 8px;
        border: 1px solid #ccc;
    }

    #showBazaarModal table.bazaar-table th,
    #bazaar-enhancer-container table.top-cheapest-table th {
        background-color: #f2f2f2;
    }

    .dark-mode #showBazaarModal table.bazaar-table th,
    .dark-mode #showBazaarModal table.bazaar-table td,
    .dark-mode #bazaar-enhancer-container table.top-cheapest-table th,
    .dark-mode #bazaar-enhancer-container table.top-cheapest-table td {
        background-color: #2a2a2a;
        color: #f0f0f0;
    }

    .dark-mode #showBazaarModal table.bazaar-table th,
    .dark-mode #bazaar-enhancer-container table.top-cheapest-table th {
        background-color: #333;
    }

        #mobileBazaarButton,
        #desktopBazaarButton {
            padding: 6px 10px;
            font-size: 12px;
            border-radius: 4px;
            margin: 5px;
            background-color: #4caf50;
            color: white;
            border: none;
            cursor: pointer;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
            transition: background-color 0.3s, opacity 0.3s;
        }

        #mobileBazaarButton:hover,
        #desktopBazaarButton:hover {
            background-color: #45a049;
            opacity: 0.9;
        }

    #showBazaarModal .pagination-button,
    #bazaar-enhancer-container .pagination-button {
        padding: 6px 10px;
        font-size: 12px;
        margin: 5px;
        border: 1px solid #ccc;
        background-color: #4caf50;
        color: white;
        border-radius: 4px;
        cursor: pointer;
        transition: background-color 0.3s, opacity 0.3s;
    }

    #showBazaarModal .pagination-button:disabled,
    #bazaar-enhancer-container .pagination-button:disabled {
        background-color: #ccc;
        cursor: not-allowed;
    }

    #showBazaarModal .pagination-button:hover:not(:disabled),
    #bazaar-enhancer-container .pagination-button:hover:not(:disabled) {
        background-color: #45a049;
    }

    @media screen and (max-width: 768px) {
        #showBazaarModal #modal-content {
            padding: 15px;
        }

        #bazaarButton {
            padding: 5px 8px;
            font-size: 12px;
        }

        #showBazaarModal table.bazaar-table th,
        #bazaar-enhancer-container table.top-cheapest-table th,
        #showBazaarModal table.bazaar-table td,
        #bazaar-enhancer-container table.top-cheapest-table td {
            padding: 6px;
        }
    }


    #showBazaarModal .loading-spinner,
    #bazaar-enhancer-container .loading-spinner {
        border: 4px solid #f3f3f3;
        border-top: 4px solid #3498db;
        border-radius: 50%;
        width: 24px;
        height: 24px;
        animation: spin 2s linear infinite;
        display: inline-block;
        margin-left: 10px;
    }
    `;
        document.head.appendChild(style);
    }

    function adjustBazaarTableTheme() {
        const isDarkMode = document.body.classList.contains('dark-mode');
        const bazaarTable = document.querySelector('.bazaar-table');

        if (isDarkMode && bazaarTable) {
            bazaarTable.style.backgroundColor = '#1c1c1c';
            bazaarTable.style.color = '#f0f0f0';
            bazaarTable.querySelectorAll('th').forEach(th => {
                th.style.backgroundColor = '#444';
                th.style.color = '#ffffff';
            });
            bazaarTable.querySelectorAll('tr:nth-child(even)').forEach(tr => {
                tr.style.backgroundColor = '#2a2a2a';
            });
            bazaarTable.querySelectorAll('tr:nth-child(odd)').forEach(tr => {
                tr.style.backgroundColor = '#1e1e1e';
            });
            bazaarTable.querySelectorAll('td a').forEach(a => {
                a.style.color = '#4ea8de';
            });
        } else if (bazaarTable) {
            bazaarTable.style.backgroundColor = '#fff';
            bazaarTable.style.color = '#000';
            bazaarTable.querySelectorAll('th').forEach(th => {
                th.style.backgroundColor = '#f2f2f2';
                th.style.color = '#000';
            });
            bazaarTable.querySelectorAll('tr:nth-child(even)').forEach(tr => {
                tr.style.backgroundColor = '#f9f9f9';
            });
            bazaarTable.querySelectorAll('tr:nth-child(odd)').forEach(tr => {
                tr.style.backgroundColor = '#fff';
            });
            bazaarTable.querySelectorAll('td a').forEach(a => {
                a.style.color = '#007bff';
            });
        }
    }

    function adjustTopCheapestTableTheme() {
        const isDarkMode = document.body.classList.contains('dark-mode');
        const topCheapestTable = document.querySelector('.top-cheapest-table');

        if (isDarkMode && topCheapestTable) {
            topCheapestTable.style.backgroundColor = '#1c1c1c';
            topCheapestTable.style.color = '#f0f0f0';
            topCheapestTable.querySelectorAll('th').forEach(th => {
                th.style.backgroundColor = '#444';
                th.style.color = '#ffffff';
            });
            topCheapestTable.querySelectorAll('tr:nth-child(even)').forEach(tr => {
                tr.style.backgroundColor = '#2a2a2a';
            });
            topCheapestTable.querySelectorAll('tr:nth-child(odd)').forEach(tr => {
                tr.style.backgroundColor = '#1e1e1e';
            });
            topCheapestTable.querySelectorAll('td a').forEach(a => {
                a.style.color = '#4ea8de';
            });
        } else if (topCheapestTable) {
            topCheapestTable.style.backgroundColor = '#fff';
            topCheapestTable.style.color = '#000';
            topCheapestTable.querySelectorAll('th').forEach(th => {
                th.style.backgroundColor = '#f2f2f2';
                th.style.color = '#000';
            });
            topCheapestTable.querySelectorAll('tr:nth-child(even)').forEach(tr => {
                tr.style.backgroundColor = '#f9f9f9';
            });
            topCheapestTable.querySelectorAll('tr:nth-child(odd)').forEach(tr => {
                tr.style.backgroundColor = '#fff';
            });
            topCheapestTable.querySelectorAll('td a').forEach(a => {
                a.style.color = '#007bff';
            });
        }
    }

    function adjustBazaarEnhancerContainerTheme() {
        const container = document.getElementById('bazaar-enhancer-container');
        const isDarkMode = document.body.classList.contains('dark-mode');

        if (container) {
            if (isDarkMode) {
                container.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';
                container.style.color = '#f0f0f0';
                container.style.border = '1px solid rgba(255, 255, 255, 0.1)';
                container.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.4)';
            } else {
                container.style.backgroundColor = '#ffffff';
                container.style.color = '#000000';
                container.style.border = '1px solid #ddd';
                container.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.1)';
            }
        }
    }


    function observeDarkMode() {
        const observer = new MutationObserver(() => {
            adjustBazaarTableTheme();
            adjustTopCheapestTableTheme();
            adjustBazaarEnhancerContainerTheme();
        });

        observer.observe(document.body, { attributes: true, attributeFilter: ['class'] });
    }

})();