import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
/** Safely convert an unknown value to string, falling back to a default. */
function toStr(val, fallback) {
    if (typeof val === 'string') {
        return val;
    }
    if (typeof val === 'number') {
        return String(val);
    }
    return fallback;
}
/** Map categories to their static fallback JSON files in src/config/ */
const STATIC_FALLBACK_MAP = {
    frameworks: ['framework-registry/index.json', 'build-tools-catalog.json'],
    security: ['known-cves.json', 'security-patterns.json'],
    pricing: ['ai-model-pricing.json', 'llm-providers.json'],
    tooling: ['saas-registry.json', 'mcp-catalog.json'],
    patterns: ['architecture-patterns.json', 'quality-principles.json'],
    compliance: ['security-patterns.json'], // reuse security for compliance fallback
    platforms: ['deploy-platforms.json'],
};
/**
 * Load static fallback items from JSON config files.
 * Converts JSON entries into KnowledgeItem format.
 */
export async function loadStaticFallback(category) {
    const files = STATIC_FALLBACK_MAP[category];
    const items = [];
    for (const file of files) {
        try {
            const configDir = join(import.meta.dirname, '../../config');
            const raw = await readFile(join(configDir, file), 'utf-8');
            const data = JSON.parse(raw);
            const converted = convertStaticToItems(data, category, file);
            items.push(...converted);
        }
        catch {
            // File doesn't exist or can't parse — skip silently
        }
    }
    return items;
}
/**
 * Convert a static JSON config into KnowledgeItem format.
 * Handles various JSON structures found in src/config/.
 */
function convertStaticToItems(data, category, sourceFile) {
    const items = [];
    const now = new Date().toISOString();
    // Handle arrays at top level
    if (Array.isArray(data)) {
        for (const entry of data) {
            const rawId = entry.id ?? entry.name ?? items.length;
            const id = typeof rawId === 'string' || typeof rawId === 'number'
                ? String(rawId)
                : String(items.length);
            items.push({
                id: `static-${category}-${id}`,
                category,
                title: toStr(entry.name ?? entry.title ?? entry.id, 'Unknown'),
                description: toStr(entry.description ?? entry.summary, ''),
                sourceUrl: undefined,
                applicableTargets: inferTargetsFromStatic(entry),
                severity: 'recommended',
                tags: extractTagsFromStatic(entry),
                fetchedAt: now,
            });
        }
        return items;
    }
    // Handle object with named entries (like framework-registry)
    for (const [key, value] of Object.entries(data)) {
        if (typeof value === 'object' && value !== null) {
            const entry = value;
            items.push({
                id: `static-${category}-${key}`,
                category,
                title: toStr(entry.name, key),
                description: toStr(entry.description ?? entry.summary, `${key} from ${sourceFile}`),
                sourceUrl: undefined,
                applicableTargets: inferTargetsFromStatic(entry),
                severity: 'recommended',
                tags: extractTagsFromStatic(entry),
                fetchedAt: now,
            });
        }
    }
    return items;
}
function inferTargetsFromStatic(entry) {
    const type = toStr(entry.type ?? entry.target, '').toLowerCase();
    if (type.includes('frontend')) {
        return ['frontend'];
    }
    if (type.includes('backend')) {
        return ['backend'];
    }
    return ['fullstack'];
}
function extractTagsFromStatic(entry) {
    if (Array.isArray(entry.tags)) {
        return entry.tags.filter((t) => typeof t === 'string').slice(0, 10);
    }
    if (typeof entry.category === 'string') {
        return [entry.category];
    }
    return [];
}
/**
 * Merge web-fetched items with static fallback items.
 * Web items take priority. Static items fill gaps.
 * Deduplicates by title similarity.
 */
export function mergeKnowledge(webItems, staticItems) {
    if (webItems.length === 0) {
        return staticItems;
    }
    if (staticItems.length === 0) {
        return webItems;
    }
    const merged = [...webItems];
    const webTitlesLower = new Set(webItems.map((i) => i.title.toLowerCase()));
    // Add static items that don't overlap with web results
    for (const staticItem of staticItems) {
        const titleLower = staticItem.title.toLowerCase();
        const isDuplicate = webTitlesLower.has(titleLower) ||
            [...webTitlesLower].some((t) => t.includes(titleLower) || titleLower.includes(t));
        if (!isDuplicate) {
            merged.push(staticItem);
        }
    }
    return merged;
}
//# sourceMappingURL=knowledge-merger.js.map