// Planu — MCP Candidate Detector
// Scores whether a project should create an MCP server layer based on
// its ProjectKnowledge (API contracts, stack, external services, etc.).
// ---------------------------------------------------------------------------
// Keyword dictionaries
// ---------------------------------------------------------------------------
const APP_DOMAIN_KEYWORDS = {
    crm: [
        'salesforce',
        'hubspot',
        'contact',
        'customer',
        'lead',
        'account',
        'deal',
        'pipeline',
        'opportunity',
        'crm',
    ],
    billing: [
        'invoice',
        'billing',
        'subscription',
        'payment',
        'refund',
        'chargeback',
        'pricing',
        'plan',
        'coupon',
    ],
    inventory: [
        'stock',
        'warehouse',
        'sku',
        'shipment',
        'order',
        'fulfillment',
        'inventory',
        'supply-chain',
    ],
    healthcare: [
        'patient',
        'medical',
        'health',
        'clinic',
        'hospital',
        'appointment',
        'ehr',
        'fhir',
        'hipaa',
    ],
    ecommerce: [
        'product',
        'cart',
        'catalog',
        'storefront',
        'marketplace',
        'shopify',
        'woocommerce',
        'checkout',
    ],
    'project-mgmt': [
        'jira',
        'asana',
        'sprint',
        'task',
        'issue',
        'backlog',
        'kanban',
        'agile',
        'ticket',
    ],
    social: [
        'chat',
        'messaging',
        'feed',
        'timeline',
        'friend',
        'follower',
        'community',
        'post',
        'comment',
    ],
    gaming: ['game', 'player', 'leaderboard', 'match', 'lobby', 'multiplayer', 'score', 'level'],
    iot: ['mqtt', 'sensor', 'device', 'firmware', 'telemetry', 'smart-home', 'zigbee'],
    hr: ['employee', 'payroll', 'recruitment', 'hiring', 'onboarding', 'timesheet', 'leave'],
    logistics: [
        'logistics',
        'shipping',
        'delivery',
        'warehouse',
        'tracking',
        'fleet',
        'route',
        'freight',
    ],
    media: ['content', 'publishing', 'editorial', 'streaming', 'video', 'podcast', 'cms', 'drm'],
    government: ['government', 'citizen', 'municipal', 'permit', 'license', 'e-gov', 'fedramp'],
    generic: [],
};
const API_FRAMEWORK_KEYWORDS = [
    'express',
    'fastify',
    'nestjs',
    'koa',
    'hapi',
    'django',
    'flask',
    'fastapi',
    'rails',
    'spring',
    'gin',
    'fiber',
    'echo',
    'actix',
    'rocket',
];
const BACKEND_APP_TYPES = ['backend', 'api', 'server', 'worker'];
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
/** Normalize a string for keyword matching (lowercase, trim). */
function normalize(s) {
    return s.toLowerCase().trim();
}
/**
 * Build a flat searchable corpus from ProjectKnowledge.
 * Defensive against partial data — callers may pass incomplete objects (e.g., tests with `as never`).
 */
function buildCorpus(knowledge) {
    /* eslint-disable @typescript-eslint/no-unnecessary-condition */
    const parts = [
        knowledge.language ?? '',
        knowledge.framework ?? '',
        knowledge.orm ?? '',
        knowledge.database ?? '',
        knowledge.packageManager ?? '',
        ...(knowledge.stack ?? []),
        ...(knowledge.externalServices ?? []),
        ...(knowledge.layers ?? []),
        ...Object.keys(knowledge.conventions ?? {}),
        ...Object.values(knowledge.conventions ?? {}),
        ...Object.keys(knowledge.tooling ?? {}),
        ...Object.values(knowledge.tooling ?? {}),
        ...(knowledge.apiContracts ?? []).map((c) => `${c.type} ${c.endpoints.join(' ')}`),
        ...(knowledge.apps ?? []).flatMap((a) => [
            a.name,
            a.type,
            a.language,
            a.framework ?? '',
            a.orm ?? '',
        ]),
    ];
    /* eslint-enable @typescript-eslint/no-unnecessary-condition */
    return normalize(parts.join(' '));
}
/** Check if corpus contains any keyword from list. */
function matchesAny(corpus, keywords) {
    return keywords.some((kw) => corpus.includes(normalize(kw)));
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Detect which application domains apply to a project based on its knowledge.
 * Returns matching domains excluding 'generic'.
 */
export function detectAppDomains(knowledge) {
    const corpus = buildCorpus(knowledge);
    const domains = [];
    for (const [domain, keywords] of Object.entries(APP_DOMAIN_KEYWORDS)) {
        if (domain === 'generic') {
            continue;
        }
        if (matchesAny(corpus, keywords)) {
            domains.push(domain);
        }
    }
    return domains;
}
/**
 * Score whether a project is a good candidate for an MCP server layer.
 * Examines API contracts, stack, external services, app types, and detected domains.
 */
export function scoreMcpCandidate(knowledge) {
    /* eslint-disable @typescript-eslint/no-unnecessary-condition */
    let score = 0;
    const reasons = [];
    // API contracts defined → +3
    const contracts = knowledge.apiContracts ?? [];
    if (contracts.length > 0) {
        score += 3;
        reasons.push(`Project has ${contracts.length} API contracts defined`);
    }
    // ORM + known database → +3
    const orm = knowledge.orm ?? null;
    const db = knowledge.database ?? 'unknown';
    if (orm && db !== 'unknown') {
        score += 3;
        reasons.push(`Project uses ${orm} with ${db}`);
    }
    // Backend/API/server/worker apps → +2
    const apps = knowledge.apps ?? [];
    const hasBackendApp = apps.some((a) => BACKEND_APP_TYPES.some((t) => a.type.toLowerCase().includes(t)));
    if (hasBackendApp) {
        score += 2;
        reasons.push('Project has backend/API applications');
    }
    // External services → +2
    const services = knowledge.externalServices ?? [];
    if (services.length > 0) {
        score += 2;
        reasons.push(`Project integrates ${services.length} external services`);
    }
    // API framework in stack → +2
    const stack = knowledge.stack ?? [];
    const framework = knowledge.framework ?? '';
    const allStackItems = [...stack, framework].map((s) => normalize(s));
    const matchedFramework = API_FRAMEWORK_KEYWORDS.find((fw) => allStackItems.some((item) => item.includes(fw)));
    if (matchedFramework) {
        score += 2;
        reasons.push(`Project uses ${matchedFramework} (API framework)`);
    }
    // Detected app domains → +2
    const detectedDomains = detectAppDomains(knowledge);
    if (detectedDomains.length > 0) {
        score += 2;
        reasons.push(`Detected domains: ${detectedDomains.join(', ')}`);
    }
    // Already uses MCP ecosystem → +1
    const mcps = knowledge.availableMcps ?? [];
    if (mcps.length > 0) {
        score += 1;
        reasons.push('Project already uses MCP ecosystem');
    }
    /* eslint-enable @typescript-eslint/no-unnecessary-condition */
    return {
        score,
        reasons,
        detectedDomains,
        isStrongCandidate: score >= 5,
        isSoftCandidate: score >= 3 && score < 5,
    };
}
//# sourceMappingURL=mcp-candidate-detector.js.map