🧠 Memory Deck Helper

Reveals and remembers card faces, paints them on their backs permanently.

// ==UserScript==
// @name         🧠 Memory Deck Helper
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Reveals and remembers card faces, paints them on their backs permanently.
// @author       GPT-5
// @match        https://eclesiar.com/dashboard
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';
    const DEBUG = false; // set to true to enable console logs

    // === 1. STORAGE FUNCTIONS ===
    let cardMemory = {};

    function loadMemory() {
        if (DEBUG) console.log("[DEBUG][loadMemory] Loading memory from storage...");
        cardMemory = GM_getValue("memoryDeck", {});
        if (DEBUG) console.log("[DEBUG][loadMemory] Loaded memory:", cardMemory);
    }

    function saveMemory() {
        if (DEBUG) console.log("[DEBUG][saveMemory] Saving memory...");
        GM_setValue("memoryDeck", cardMemory);
    }

    // === 2. CARD DATA HANDLING ===
    function paintCardBack(index, imgUrl, qtyText) {
        console.log(`[DEBUG][paintCardBack] Painting card back for index=${index}`);
        const cardBack = document.querySelector(`.memory-card[data-index="${index}"] .card-back`);
        if (!cardBack) {
            console.warn(`[DEBUG][paintCardBack] Card back not found for index ${index}`);
            return;
        }

        if (cardBack.dataset.processedImg === imgUrl && cardBack.dataset.processedQty === qtyText) {
            console.log(`[DEBUG][paintCardBack] Skipping (already painted) for index ${index}`);
            return;
        }

        cardBack.dataset.processedImg = imgUrl || "";
        cardBack.dataset.processedQty = qtyText || "";

        if (imgUrl) {
            cardBack.style.backgroundImage = `url("${imgUrl}")`;
            cardBack.style.backgroundSize = "contain";
            cardBack.style.backgroundRepeat = "no-repeat";
            cardBack.style.backgroundPosition = "center";
            cardBack.style.backgroundColor = "#cd983d";
            console.log(`[DEBUG][paintCardBack] Applied image and background to card ${index}`);
        }

        if (getComputedStyle(cardBack).position === "static") {
            cardBack.style.position = "relative";
            console.log(`[DEBUG][paintCardBack] Set position: relative for card ${index}`);
        }

        let overlay = cardBack.querySelector(".memory-qty-overlay");
        if (!overlay) {
            overlay = document.createElement("div");
            overlay.className = "memory-qty-overlay";
            overlay.style.position = "absolute";
            overlay.style.bottom = "5px";
            overlay.style.left = "0";
            overlay.style.width = "100%";
            overlay.style.textAlign = "center";
            overlay.style.fontSize = "14px";
            overlay.style.fontWeight = "bold";
            overlay.style.color = "white";
            overlay.style.textShadow = "0 0 3px black";
            cardBack.appendChild(overlay);
            console.log(`[DEBUG][paintCardBack] Created new overlay for card ${index}`);
        }
        overlay.textContent = qtyText || "";
    }

    function recordCard(cardEl) {
        if (!cardEl) return;
        const index = cardEl.dataset.index;
        if (DEBUG) console.log(`[DEBUG][recordCard] Recording card index=${index}`);
        if (!index) return;

        const imgEl = cardEl.querySelector("img");
        const qtyEl = cardEl.querySelector(".memory-qty");
        const imgUrl = imgEl ? imgEl.getAttribute("src") : null;
        const qtyText = qtyEl ? qtyEl.textContent.trim() : "";

        if (DEBUG) console.log(`[DEBUG][recordCard] Extracted imgUrl=${imgUrl}, qtyText=${qtyText}`);

        if (!imgUrl) {
            if (DEBUG) console.log(`[DEBUG][recordCard] No imgUrl found for card ${index}, skipping`);
            return;
        }

        if (!cardMemory[index] ||
            cardMemory[index].imgUrl !== imgUrl ||
            cardMemory[index].qtyText !== qtyText) {
            cardMemory[index] = { imgUrl, qtyText };
            if (DEBUG) console.log(`[DEBUG][recordCard] Stored card ${index}:`, cardMemory[index]);
            saveMemory();
        } else {
            if (DEBUG) console.log(`[DEBUG][recordCard] Card ${index} already recorded, skipping update`);
        }

        paintCardBack(index, imgUrl, qtyText);
    }

    function repaintAllCards() {
        console.log("[DEBUG][repaintAllCards] Repainting all stored cards...");
        for (const index in cardMemory) {
            const { imgUrl, qtyText } = cardMemory[index];
            paintCardBack(index, imgUrl, qtyText);
        }
    }

    // === 3. DETECTION FUNCTIONS ===
    function scanFlippedCards() {
        if (DEBUG) console.log("[DEBUG][scanFlippedCards] Scanning for flipped cards...");
        const flippedCards = document.querySelectorAll(".memory-card.is-flipped");
        if (DEBUG) console.log(`[DEBUG][scanFlippedCards] Found ${flippedCards.length} flipped cards`);

        flippedCards.forEach(cardEl => {
            if (DEBUG) console.log("[DEBUG][scanFlippedCards] Card HTML:", cardEl.outerHTML);
            recordCard(cardEl);
        });
    }

    function observeGrid(grid) {
        console.log("[DEBUG][observeGrid] Starting MutationObserver...");
        const observer = new MutationObserver(() => {
            console.log("[DEBUG][observeGrid] Mutation detected, rescanning...");
            scanFlippedCards();
        });
        observer.observe(grid, { childList: true, subtree: true, attributes: true });
    }

    // === 4. INITIALIZATION ===
    function init() {
        console.log("[DEBUG][init] Script started");
        const grid = document.querySelector("#memoryGridDesktop");
        if (!grid) {
            console.warn("[DEBUG][init] Memory grid not found, aborting");
            return;
        }

        loadMemory();
        repaintAllCards();
        scanFlippedCards();
        observeGrid(grid);

        console.log("[DEBUG][init] Initialization complete");
    }

    function clearMemory() {
        console.log("[DEBUG][clearMemory] Clearing saved memory...");
        cardMemory = {};
        GM_setValue("memoryDeck", cardMemory);

        // Also visually reset all card backs
        const allCards = document.querySelectorAll(".memory-card .card-back");
        allCards.forEach(cardBack => {
            cardBack.style.backgroundImage = "";
            cardBack.style.backgroundColor = "";
            const overlay = cardBack.querySelector(".memory-qty-overlay");
            if (overlay) overlay.remove();
            delete cardBack.dataset.processedImg;
            delete cardBack.dataset.processedQty;
        });

        console.log("[DEBUG][clearMemory] Memory cleared and card backs reset");
    }

    // === Add Clear Memory Button ===
    const header = document.querySelector(".memory-deck-header");
    if (header) {
        const btn = document.createElement("button");
        btn.textContent = "Clear Memory";
        btn.style.marginLeft = "10px";
        btn.style.padding = "5px 10px";
        btn.style.borderRadius = "6px";
        btn.style.border = "1px solid #ccc";
        btn.style.background = "#c33";
        btn.style.color = "white";
        btn.style.cursor = "pointer";
        btn.addEventListener("click", clearMemory);
        header.appendChild(btn);
        console.log("[DEBUG][init] Added Clear Memory button");
    }

    window.addEventListener("load", init);
})();