import { chromium } from "playwright";
import { ensurePlaywrightChromium } from "../../infra/python-env.js";
/** Pure parser, exposed for test injection. */
export function xiaohongshuSourceFromDom(feed) {
    const now = new Date().toISOString();
    return feed.map((f) => ({
        id: `xhs_${f.id}`,
        platform: "xiaohongshu",
        title: f.title,
        sourceUrl: `https://www.xiaohongshu.com${f.url}`,
        source: "scraper",
        scrapedAt: now,
        cover: { url: f.coverUrl, aspect: "9:16" },
        metrics: {
            views: f.views,
            likes: f.likes,
            comments: null,
            shares: null,
            fetchedAt: now,
        },
    }));
}
async function scrapeExplore(limit, signal) {
    let browser = null;
    const abortHandler = () => { browser?.close().catch(() => { }); };
    try {
        // Lazy heavy dep (I15): chromium (~150MB) isn't installed at app boot — the
        // first trends scrape downloads it on demand with progress. Idempotent +
        // fast no-op once cached. Surfaced as warn lines so a long first-run
        // download isn't a silent stall (no UI bus is reachable from this leaf
        // scraper). If the install fails, chromium.launch() below still produces the
        // canonical "Executable doesn't exist …" error the caller already handles.
        await ensurePlaywrightChromium({
            onProgress: (line) => { if (line)
                console.warn(`[xiaohongshu] ${line}`); },
        }).catch((e) => {
            console.warn(`[xiaohongshu] playwright install failed: ${e instanceof Error ? e.message : String(e)}`);
        });
        browser = await chromium.launch({ headless: true });
        signal?.addEventListener("abort", abortHandler);
        const ctx = await browser.newContext({
            userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15",
            viewport: { width: 1366, height: 900 },
        });
        const page = await ctx.newPage();
        if (signal?.aborted)
            throw new Error("aborted");
        await page.goto("https://www.xiaohongshu.com/explore", { waitUntil: "domcontentloaded", timeout: 30_000 });
        await page.waitForSelector('section[class*="note-item"], a[href*="/explore/"]', { timeout: 10_000 }).catch((e) => {
            console.warn(`[xiaohongshu] waitForSelector failed: ${e instanceof Error ? e.message : String(e)}`);
        });
        const feed = await page.evaluate((max) => {
            const anchors = Array.from(document.querySelectorAll('a[href*="/explore/"]'));
            const seen = new Set();
            const out = [];
            for (const a of anchors) {
                const href = a.getAttribute("href") ?? "";
                const idMatch = href.match(/\/explore\/([a-zA-Z0-9_-]+)/);
                if (!idMatch)
                    continue;
                const id = idMatch[1];
                if (seen.has(id))
                    continue;
                seen.add(id);
                const titleEl = a.querySelector('[class*="title"], [class*="footer"]');
                const imgEl = a.querySelector("img");
                if (!titleEl || !imgEl)
                    continue;
                out.push({
                    id,
                    title: titleEl.textContent?.trim() ?? "",
                    url: href.startsWith("/") ? href : `/explore/${id}`,
                    coverUrl: imgEl.getAttribute("src") ?? "",
                    likes: null,
                    views: null,
                });
                if (out.length >= max)
                    break;
            }
            return out;
        }, limit);
        return feed;
    }
    finally {
        signal?.removeEventListener("abort", abortHandler);
        await browser?.close().catch(() => { });
    }
}
export const xiaohongshuSource = {
    platform: "xiaohongshu",
    async collect({ limit, signal }) {
        const feed = await scrapeExplore(limit, signal);
        return xiaohongshuSourceFromDom(feed);
    },
};
//# sourceMappingURL=xiaohongshu.js.map