import { PNG } from 'pngjs';
import pixelmatch from 'pixelmatch';
import { z } from 'zod';
import { config } from '../../config.js';
import { readBaseline, resolveBaselinePath } from '../../lib/baselines.js';
import { errorResult, jsonResult, toErrorMessage } from '../shared.js';
import { browserManager } from './browserManager.js';
function toDataUri(png) {
    return `data:image/png;base64,${png.toString('base64')}`;
}
export function comparePngBuffers(baselinePng, currentPng, threshold = 0.1) {
    const baseline = PNG.sync.read(baselinePng);
    const current = PNG.sync.read(currentPng);
    if (baseline.width !== current.width || baseline.height !== current.height) {
        throw new Error(`Screenshot dimensions differ from baseline (${baseline.width}x${baseline.height} vs ${current.width}x${current.height}). ` +
            'Recapture the baseline at the same viewport/selector size.');
    }
    const { width, height } = baseline;
    const diff = new PNG({ width, height });
    const mismatchedPixels = pixelmatch(baseline.data, current.data, diff.data, width, height, {
        threshold,
    });
    const total = width * height;
    const mismatchPercent = total === 0 ? 0 : (mismatchedPixels / total) * 100;
    return {
        width,
        height,
        mismatchedPixels,
        mismatchPercent,
        diffPng: PNG.sync.write(diff),
    };
}
export function registerBrowserVisualDiffTool(server) {
    server.registerTool('browser_visual_diff', {
        title: 'Visual Screenshot Diff',
        description: 'Capture the current page/element and compare it to a previously saved baseline with pixelmatch. Returns mismatch stats and a diff PNG data URI.',
        inputSchema: {
            name: z.string().min(1).describe('Baseline name previously saved with browser_screenshot_baseline.'),
            selector: z.string().optional().describe('Optional CSS selector to screenshot for comparison.'),
            fullPage: z
                .boolean()
                .optional()
                .default(false)
                .describe('Capture the full scrollable page when selector is omitted.'),
            threshold: z
                .number()
                .min(0)
                .max(1)
                .optional()
                .default(0.1)
                .describe('pixelmatch threshold (0–1). Lower is stricter.'),
        },
    }, async ({ name, selector, fullPage, threshold }) => {
        try {
            const baselinePng = readBaseline(name);
            const session = await browserManager.getSession();
            let currentPng;
            if (selector) {
                const element = await session.page.locator(selector).first();
                await element.waitFor({ state: 'visible', timeout: 5000 });
                currentPng = await element.screenshot({ type: 'png' });
            }
            else {
                currentPng = await session.page.screenshot({ fullPage, type: 'png' });
            }
            const comparison = comparePngBuffers(baselinePng, currentPng, threshold ?? 0.1);
            const diffDataUri = toDataUri(comparison.diffPng);
            return jsonResult({
                name,
                baselinePath: resolveBaselinePath(name),
                selector: selector ?? null,
                width: comparison.width,
                height: comparison.height,
                mismatchedPixels: comparison.mismatchedPixels,
                mismatchPercent: Number(comparison.mismatchPercent.toFixed(4)),
                passed: comparison.mismatchedPixels === 0,
                threshold: threshold ?? 0.1,
                diffDataUri,
                truncatedDiffDataUri: diffDataUri.length > config.maxToolOutputChars
                    ? `${diffDataUri.slice(0, config.maxToolOutputChars)}...`
                    : diffDataUri,
            });
        }
        catch (error) {
            return errorResult(toErrorMessage(error));
        }
    });
}
//# sourceMappingURL=visualDiff.js.map