// Planu — Web Fetcher: Universal Docs Intelligence Engine (SPEC-382)
import { consultDocsImpl } from './docs-fetcher.js';
const BEST_PRACTICE_PATTERNS = [
    /\bbest practice[s]?\b/i,
    /\brecommended?\b/i,
    /\byou should\b/i,
    /\balways\b.{0,40}\b(use|prefer|ensure|check)/i,
    /\bprefer\b.{0,40}\bover\b/i,
    /\buse\b.{0,20}\bfor\b.{0,40}/i,
];
const ANTI_PATTERN_PATTERNS = [
    /\bavoid\b/i,
    /\bdeprecated\b/i,
    /\bdo not\b/i,
    /\bnever\b/i,
    /\bnot recommended\b/i,
    /\bobsolete\b/i,
];
const CONVENTION_PATTERNS = [
    /\bconvention\b/i,
    /\bstyle\b.{0,20}\bguid/i,
    /\bnaming\b/i,
    /\bformat\b.{0,20}\bshould\b/i,
    /\bfollow.{0,20}\bpattern\b/i,
    /\bfile structure\b/i,
];
const VERSION_PATTERNS = [
    /\bv?\d+(\.\d+){0,2}\b.{0,60}\b(migration|upgrade|breaking|changed)\b/i,
    /\b(migration|upgrade|breaking change)\b.{0,60}\bv?\d+(\.\d+){0,2}\b/i,
    /\bdeprecated in\b.{0,30}\bv?\d+/i,
];
const TOOL_NAME_PATTERNS = /\b(npm|pnpm|yarn|npx|pip|cargo|brew|apt|go get)\b.{0,80}/i;
function splitIntoLines(text) {
    return text
        .split(/[\n.!?]/)
        .map((l) => l.trim())
        .filter((l) => l.length > 15 && l.length < 300);
}
function stripHtml(html) {
    return html
        .replace(/<script[\s\S]*?<\/script>/gi, '')
        .replace(/<style[\s\S]*?<\/style>/gi, '')
        .replace(/<[^>]+>/g, ' ')
        .replace(/&[a-z]+;/gi, ' ')
        .replace(/\s+/g, ' ')
        .trim();
}
function matchesAny(line, patterns) {
    return patterns.some((p) => p.test(line));
}
function dedup(items) {
    return [...new Set(items)];
}
export function extractStructuredDocs(html, tech) {
    const text = stripHtml(html);
    const lines = splitIntoLines(text);
    const bestPractices = [];
    const antiPatterns = [];
    const conventions = [];
    const versionNotes = [];
    const toolingRecommendations = [];
    for (const line of lines) {
        if (matchesAny(line, ANTI_PATTERN_PATTERNS)) {
            antiPatterns.push(line);
        }
        else if (matchesAny(line, BEST_PRACTICE_PATTERNS)) {
            bestPractices.push(line);
        }
        else if (matchesAny(line, CONVENTION_PATTERNS)) {
            conventions.push(line);
        }
        if (matchesAny(line, VERSION_PATTERNS)) {
            versionNotes.push(line);
        }
        if (TOOL_NAME_PATTERNS.test(line)) {
            toolingRecommendations.push(line);
        }
    }
    return {
        tech,
        docsUrl: '',
        bestPractices: dedup(bestPractices).slice(0, 10),
        antiPatterns: dedup(antiPatterns).slice(0, 10),
        conventions: dedup(conventions).slice(0, 10),
        versionNotes: dedup(versionNotes).slice(0, 5),
        toolingRecommendations: dedup(toolingRecommendations).slice(0, 5),
        source: 'discovered',
        fetchedAt: new Date().toISOString(),
        stale: false,
    };
}
export function buildFallbackResult(tech) {
    return {
        tech,
        docsUrl: '',
        bestPractices: [],
        antiPatterns: [],
        conventions: [],
        versionNotes: [],
        toolingRecommendations: [],
        source: 'fallback',
        fetchedAt: new Date().toISOString(),
        stale: true,
    };
}
async function fetchOneTech(tech, timeoutMs) {
    try {
        const controller = new AbortController();
        const timer = setTimeout(() => {
            controller.abort();
        }, timeoutMs);
        let result;
        try {
            const docsResult = await consultDocsImpl(tech, tech);
            const html = [docsResult.summary, ...docsResult.bestPractices].join('\n');
            result = extractStructuredDocs(html, tech);
            result.docsUrl = docsResult.docsUrl;
            result.source = docsResult.source === 'local-fallback' ? 'fallback' : 'registry';
            result.stale = docsResult.stale ?? false;
            result.fetchedAt = docsResult.fetchedAt ?? new Date().toISOString();
        }
        finally {
            clearTimeout(timer);
        }
        return result;
    }
    catch {
        return buildFallbackResult(tech);
    }
}
export async function fetchDocsBatch(techs, options) {
    const timeoutMs = options?.timeout ?? 10_000;
    const concurrency = options?.concurrency ?? 3;
    const results = new Map();
    for (let i = 0; i < techs.length; i += concurrency) {
        const batch = techs.slice(i, i + concurrency);
        const settled = await Promise.allSettled(batch.map((tech) => fetchOneTech(tech, timeoutMs)));
        for (let j = 0; j < batch.length; j++) {
            const tech = batch[j];
            if (tech === undefined) {
                continue;
            }
            const outcome = settled[j];
            if (outcome === undefined || outcome.status === 'rejected') {
                results.set(tech, buildFallbackResult(tech));
            }
            else {
                results.set(tech, outcome.value);
            }
        }
    }
    return results;
}
//# sourceMappingURL=docs-intelligence.js.map