import { spawnSync } from 'child_process';
import { loadPhoton } from '../../shared/images/photon.js';
import { clipboard } from './clipboard-native.js';
const SUPPORTED_IMAGE_MIME_TYPES = ['image/png', 'image/jpeg', 'image/webp', 'image/gif'];
const DEFAULT_LIST_TIMEOUT_MS = 1000;
const DEFAULT_READ_TIMEOUT_MS = 3000;
const DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
export function isWaylandSession(env = process.env) {
    return Boolean(env.WAYLAND_DISPLAY) || env.XDG_SESSION_TYPE === 'wayland';
}
function baseMimeType(mimeType) {
    return mimeType.split(';')[0]?.trim().toLowerCase() ?? mimeType.toLowerCase();
}
export function extensionForImageMimeType(mimeType) {
    switch (baseMimeType(mimeType)) {
        case 'image/png':
            return 'png';
        case 'image/jpeg':
            return 'jpg';
        case 'image/webp':
            return 'webp';
        case 'image/gif':
            return 'gif';
        default:
            return null;
    }
}
function selectPreferredImageMimeType(mimeTypes) {
    const normalized = mimeTypes
        .map((t) => t.trim())
        .filter(Boolean)
        .map((t) => ({ raw: t, base: baseMimeType(t) }));
    for (const preferred of SUPPORTED_IMAGE_MIME_TYPES) {
        const match = normalized.find((t) => t.base === preferred);
        if (match) {
            return match.raw;
        }
    }
    const anyImage = normalized.find((t) => t.base.startsWith('image/'));
    return anyImage?.raw ?? null;
}
function isSupportedImageMimeType(mimeType) {
    const base = baseMimeType(mimeType);
    return SUPPORTED_IMAGE_MIME_TYPES.some((t) => t === base);
}
/**
 * Convert unsupported image formats to PNG using Photon.
 * Returns null if conversion is unavailable or fails.
 */
async function convertToPng(bytes) {
    const photon = await loadPhoton();
    if (!photon) {
        return null;
    }
    try {
        const image = photon.PhotonImage.new_from_byteslice(bytes);
        try {
            return image.get_bytes();
        }
        finally {
            image.free();
        }
    }
    catch {
        return null;
    }
}
function runCommand(command, args, options) {
    const timeoutMs = options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS;
    const maxBufferBytes = options?.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;
    const result = spawnSync(command, args, {
        timeout: timeoutMs,
        maxBuffer: maxBufferBytes
    });
    if (result.error) {
        return { ok: false, stdout: Buffer.alloc(0) };
    }
    if (result.status !== 0) {
        return { ok: false, stdout: Buffer.alloc(0) };
    }
    const stdout = Buffer.isBuffer(result.stdout)
        ? result.stdout
        : Buffer.from(result.stdout ?? '', typeof result.stdout === 'string' ? 'utf-8' : undefined);
    return { ok: true, stdout };
}
/**
 * PowerShell fallback for Windows image reading.
 * Handles BMP/DIB format (Snipping Tool, Win+Shift+S) and cases where the
 * native @mariozechner/clipboard module is unavailable or returns hasImage()=false.
 * Saves clipboard image as PNG via System.Windows.Forms and returns base64-encoded bytes.
 */
function readClipboardImageViaPowerShell() {
    const result = runCommand('powershell.exe', [
        '-NoProfile',
        '-Command',
        'Add-Type -AssemblyName System.Windows.Forms; ' +
            '$img = [System.Windows.Forms.Clipboard]::GetImage(); ' +
            'if ($img -eq $null) { exit 1 }; ' +
            '$ms = New-Object System.IO.MemoryStream; ' +
            '$img.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); ' +
            '[System.Convert]::ToBase64String($ms.ToArray())'
    ], { timeoutMs: 8000 });
    if (!result.ok || result.stdout.length === 0)
        return null;
    try {
        const base64 = result.stdout.toString('utf-8').trim();
        const bytes = Buffer.from(base64, 'base64');
        if (bytes.length === 0)
            return null;
        return { bytes, mimeType: 'image/png' };
    }
    catch {
        return null;
    }
}
function readClipboardImageViaWlPaste() {
    const list = runCommand('wl-paste', ['--list-types'], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });
    if (!list.ok) {
        return null;
    }
    const types = list.stdout
        .toString('utf-8')
        .split(/\r?\n/)
        .map((t) => t.trim())
        .filter(Boolean);
    const selectedType = selectPreferredImageMimeType(types);
    if (!selectedType) {
        return null;
    }
    const data = runCommand('wl-paste', ['--type', selectedType, '--no-newline']);
    if (!data.ok || data.stdout.length === 0) {
        return null;
    }
    return { bytes: data.stdout, mimeType: baseMimeType(selectedType) };
}
function readClipboardImageViaXclip() {
    const targets = runCommand('xclip', ['-selection', 'clipboard', '-t', 'TARGETS', '-o'], {
        timeoutMs: DEFAULT_LIST_TIMEOUT_MS
    });
    let candidateTypes = [];
    if (targets.ok) {
        candidateTypes = targets.stdout
            .toString('utf-8')
            .split(/\r?\n/)
            .map((t) => t.trim())
            .filter(Boolean);
    }
    const preferred = candidateTypes.length > 0 ? selectPreferredImageMimeType(candidateTypes) : null;
    const tryTypes = preferred
        ? [preferred, ...SUPPORTED_IMAGE_MIME_TYPES]
        : [...SUPPORTED_IMAGE_MIME_TYPES];
    for (const mimeType of tryTypes) {
        const data = runCommand('xclip', ['-selection', 'clipboard', '-t', mimeType, '-o']);
        if (data.ok && data.stdout.length > 0) {
            return { bytes: data.stdout, mimeType: baseMimeType(mimeType) };
        }
    }
    return null;
}
export async function readClipboardImage(options) {
    const env = options?.env ?? process.env;
    const platform = options?.platform ?? process.platform;
    if (env.TERMUX_VERSION) {
        return null;
    }
    let image = null;
    if (platform === 'linux' && isWaylandSession(env)) {
        image = readClipboardImageViaWlPaste() ?? readClipboardImageViaXclip();
    }
    else if (platform === 'win32') {
        // Try native module first (fast), then PowerShell fallback.
        // PowerShell catches BMP/DIB format (Snipping Tool, Win+Shift+S) which
        // hasImage() misses, and also works when the native module fails to load.
        if (clipboard?.hasImage()) {
            const imageData = await clipboard.getImageBinary();
            if (imageData && imageData.length > 0) {
                const bytes = imageData instanceof Uint8Array ? imageData : Uint8Array.from(imageData);
                image = { bytes, mimeType: 'image/png' };
            }
        }
        image ??= readClipboardImageViaPowerShell();
    }
    else {
        // macOS and other platforms
        if (!clipboard?.hasImage()) {
            return null;
        }
        const imageData = await clipboard.getImageBinary();
        if (!imageData || imageData.length === 0) {
            return null;
        }
        const bytes = imageData instanceof Uint8Array ? imageData : Uint8Array.from(imageData);
        image = { bytes, mimeType: 'image/png' };
    }
    if (!image) {
        return null;
    }
    // Convert unsupported formats (e.g., BMP from WSLg) to PNG
    if (!isSupportedImageMimeType(image.mimeType)) {
        const pngBytes = await convertToPng(image.bytes);
        if (!pngBytes) {
            return null;
        }
        return { bytes: pngBytes, mimeType: 'image/png' };
    }
    return image;
}
//# sourceMappingURL=clipboard-image.js.map