#!/usr/bin/env node
/**
 * Save a browser-generated MHTML snapshot using Chrome/Puppeteer.
 *
 * Requires a Chrome session (from chrome plugin) and connects to it via CDP.
 *
 * Usage: on_Snapshot__54_chrome_mhtml.js --url=<url>
 * Output: Writes chrome_mhtml/snapshot.mhtml
 *
 * Environment variables:
 *     CHROME_MHTML_ENABLED: Enable MHTML extraction (default: true)
 */

const fs = require('fs');
const path = require('path');
const {
    ensureNodeModuleResolution,
    getEnvBool,
    getEnvInt,
    loadConfig,
    parseArgs,
    emitArchiveResultRecord,
    writeFileAtomic,
} = require('../base/utils.js');
ensureNodeModuleResolution(module);
const { connectToPage, resolvePuppeteerModule } = require('../chrome/chrome_utils.js');
const hookConfig = loadConfig();

if (!getEnvBool('CHROME_MHTML_ENABLED', true)) {
    console.error('Skipping Chrome MHTML (CHROME_MHTML_ENABLED=False)');
    emitArchiveResultRecord('skipped', 'CHROME_MHTML_ENABLED=False');
    process.exit(0);
}

const puppeteer = resolvePuppeteerModule();

const PLUGIN_NAME = 'chrome_mhtml';
const PLUGIN_DIR = path.basename(__dirname);
const SNAP_DIR = path.resolve((hookConfig.SNAP_DIR || '.').trim());
const OUTPUT_DIR = path.join(SNAP_DIR, PLUGIN_DIR);
if (!fs.existsSync(OUTPUT_DIR)) {
    fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
process.chdir(OUTPUT_DIR);
const OUTPUT_FILE = 'snapshot.mhtml';
const CHROME_SESSION_DIR = '../chrome';

async function waitForFrameTreeSettled(page, timeoutMs) {
    const settleTimeoutMs = Math.min(Math.max(timeoutMs, 1000), 5000);
    if (typeof page.waitForNetworkIdle === 'function') {
        await page.waitForNetworkIdle({ idleTime: 500, timeout: settleTimeoutMs }).catch(() => null);
    }

    await Promise.all(page.frames().map(frame => (
        frame.waitForFunction(
            () => document.readyState === 'complete',
            { timeout: Math.min(settleTimeoutMs, 1500) }
        ).catch(() => null)
    )));
}

async function captureMhtml(timeoutMs) {
    const outputPath = path.join(OUTPUT_DIR, OUTPUT_FILE);
    let browser = null;
    const deadline = Date.now() + timeoutMs;

    try {
        const connection = await connectToPage({
            chromeSessionDir: CHROME_SESSION_DIR,
            timeoutMs,
            waitForNavigationComplete: true,
            postLoadDelayMs: 200,
            puppeteer,
        });
        browser = connection.browser;
        const page = connection.page;
        const cdpSession = connection.cdpSession;

        await waitForFrameTreeSettled(page, timeoutMs);
        await cdpSession.send('Page.enable').catch(() => null);

        const remainingMs = deadline - Date.now();
        const captureTimeoutMs = Math.max(1000, remainingMs - 5000);
        if (captureTimeoutMs <= 1000) {
            return { success: false, error: 'Chrome MHTML capture timed out' };
        }

        const snapshot = await Promise.race([
            cdpSession.send('Page.captureSnapshot', { format: 'mhtml' }),
            new Promise((_, reject) => {
                setTimeout(() => reject(new Error('Chrome MHTML capture timed out')), captureTimeoutMs);
            }),
        ]);
        const mhtmlContent = snapshot && snapshot.data;

        if (mhtmlContent && mhtmlContent.length > 100) {
            writeFileAtomic(outputPath, mhtmlContent);
            return { success: true, output: OUTPUT_FILE };
        }
        return { success: true, noresults: true, output: 'MHTML content too short or empty' };

    } catch (e) {
        return { success: false, error: `${e.name}: ${e.message}` };
    } finally {
        if (browser) {
            browser.disconnect();
        }
    }
}

async function main() {
    const args = parseArgs();
    const url = args.url;

    if (!url) {
        console.error('Usage: on_Snapshot__54_chrome_mhtml.js --url=<url>');
        emitArchiveResultRecord('failed', 'missing required args');
        process.exit(1);
    }

    try {
        const timeoutMs = getEnvInt('CHROME_MHTML_TIMEOUT', getEnvInt('TIMEOUT', 30)) * 1000;
        const result = await captureMhtml(timeoutMs);

        if (result.success) {
            if (result.noresults) {
                emitArchiveResultRecord('noresults', result.output);
                process.exit(0);
            }
            const size = fs.statSync(path.join(OUTPUT_DIR, result.output)).size;
            console.error(`Chrome MHTML saved (${size} bytes)`);
            emitArchiveResultRecord('succeeded', `${PLUGIN_DIR}/${result.output}`);
            process.exit(0);
        }

        console.error(`ERROR: ${result.error}`);
        emitArchiveResultRecord('failed', result.error);
        process.exit(1);
    } catch (e) {
        console.error(`ERROR: ${e.name}: ${e.message}`);
        emitArchiveResultRecord('failed', `${e.name}: ${e.message}`);
        process.exit(1);
    }
}

main().catch(e => {
    console.error(`Fatal error: ${e.message}`);
    emitArchiveResultRecord('failed', `${e.name}: ${e.message}`);
    process.exit(1);
});
