const fs = require('fs');
const path = require('path');
const jsdom = require('jsdom');
const { JSDOM } = jsdom;

const observerModule = require('./extension/out/observer-script.js');
const observerCode = observerModule.generateApprovalObserverScript(8080);
const rawDump = JSON.parse(fs.readFileSync('C:/Users/Variet-Worker/.gemini/antigravity/bridge/dump_html.json', 'utf8'));

// Instantiate DOM
const dom = new JSDOM(rawDump.html, { runScripts: "dangerously", pretendToBeVisual: true, url: "http://localhost/" });
const window = dom.window;
const document = window.document;

// Polyfill offsetParent for visibility check
Object.defineProperty(window.HTMLElement.prototype, 'offsetParent', {
  get() { return document.body; }
});
Object.defineProperty(window.HTMLElement.prototype, 'style', {
  get() { return { display: 'block' }; }
});

// Mock innerText (JSDOM does not fully support it, but generic walker uses nodeValue / textContent)
// Our logic uses nodeValue for TextNodes, so it will work in JSDOM out of the box!

// Setup the DOM tree to perfectly match a real Chat conversation
const titleSpan = document.querySelector('span[title^="command("]');
if(!titleSpan) {
    console.error("COULD NOT FIND command SPAN in dump?!");
    process.exit(1);
}
// Find the card container
let toolContainer = titleSpan.parentElement;
while(toolContainer && !toolContainer.className.includes("border-gray-500/10") && !toolContainer.className.includes("bg-gray-500/10")) {
    toolContainer = toolContainer.parentElement;
}
if(!toolContainer) toolContainer = titleSpan.parentElement; // fallback

// Create an AI text block just above it
const aiChat = document.createElement('div');
aiChat.className = 'markdown prose';
aiChat.innerHTML = '<p>안녕하세요! 시스템을 수정하기 위해 요청하신 작업을 시작합니다. <b>디스코드 릴레이 기능 복구</b>를 위해 스크립트를 실행하겠습니다.</p>';

// Wrap them up in the turn container
const parent = toolContainer.parentElement;
const convoWrapper = document.createElement('div');
convoWrapper.className = 'bg-agent-convo-background';
parent.insertBefore(convoWrapper, toolContainer);
convoWrapper.appendChild(aiChat);
convoWrapper.appendChild(toolContainer); // Move tool inside the convo wrapper as a sibling to AI chat

// Add action button to the tool container
const btn = document.createElement('button');
btn.innerHTML = '<span class="truncate">Allow</span>';
toolContainer.appendChild(btn);

console.log("Mock Button offsetParent:", btn.offsetParent ? btn.offsetParent.tagName : 'null');
console.log("Mock Button display:", btn.style.display);
console.log("Mock Button text:", btn.textContent);

// MOCK FETCH
const fetchCalls = [];
window.fetch = function(url, options) {
    fetchCalls.push({url, options});
    if (url.includes('/ping')) {
        return Promise.resolve({ text: function() { return Promise.resolve('pong'); } });
    }
    if (url.includes('/pending')) {
        return Promise.resolve({ json: function() { return Promise.resolve({ok: true, request_id: 'test-rid'}); } });
    }
    return Promise.resolve({ json: function() { return Promise.resolve({}); } });
};

// Polyfill offsetParent for visibility check
Object.defineProperty(window.HTMLElement.prototype, 'offsetParent', {
  get() { return document.body; }
});
Object.defineProperty(window.HTMLElement.prototype, 'style', {
  get() { return { display: 'block' }; }
});

const originalLog = console.log;
window.console.log = function(...args) {
    if (args.length > 0 && typeof args[0] === 'string' && args[0].includes("NOT MATCHED")) {
         let txt = args[1];
         let codes = [];
         if (txt) {
            for(let i=0; i<txt.length; i++) codes.push(txt.charCodeAt(i));
         }
         originalLog('[JSDOM-WIN]', args[0], `\nRAW="${txt}"\nCODES=[${codes.join(',')}]`);
    } else {
         originalLog('[JSDOM-WIN]', ...args);
    }
};

// Inject the observer
const scriptEl = document.createElement('script');
scriptEl.textContent = observerCode;
document.body.appendChild(scriptEl);

console.log("Observer injected, waiting for cycles...");
console.log("Total Buttons in DOM:", document.querySelectorAll('button').length);

// Emulate UI mutation to trigger the MutationObserver and force an instant scan()
setTimeout(() => {
    console.log("Triggering DOM mutation to force scan()...");
    document.body.appendChild(document.createElement('span'));
}, 1500);

// Give it time to finish scan().
setTimeout(() => {
    console.log("\n====== FETCH CALLS ======");
    if(fetchCalls.length === 0) console.log("NO FETCH CALLS MADE!");
    
    fetchCalls.forEach(c => {
        console.log(`\n[${c.options ? c.options.method || 'GET' : 'GET'}] ${c.url}`);
        if(c.options && c.options.body) {
            try {
                let j = JSON.parse(c.options.body);
                console.log("[BODY] request_id:", j.request_id);
                console.log("[BODY] command:", j.command);
                console.log("[BODY] description:\n" + "=".repeat(40) + "\n" + j.description + "\n" + "=".repeat(40));
            } catch(e) {
                console.log("[BODY]", c.options.body);
            }
        }
    });

    // Determine success
    const pendingCall = fetchCalls.find(c => c.url.includes('/pending'));
    if(pendingCall && pendingCall.options && pendingCall.options.body) {
        const payload = JSON.parse(pendingCall.options.body);
        if(payload.description.includes("안녕하세요!") && payload.description.includes("METHOD=TITLE_SPAN")) {
            console.log("\n✅ SUCCESS: Both Chat Body & Tool Command effectively extracted!");
            process.exit(0);
        } else {
            console.log("\n❌ FAIL: Payload description missing either chat text or command string!");
            process.exit(1);
        }
    } else {
         console.log("\n❌ FAIL: /pending never called!");
         process.exit(1);
    }
}, 4000);
