/**
 * Learning Path Recommender for Serverless Platforms
 *
 * Recommends curated learning resources based on skill level, platform,
 * and best practices for serverless development.
 */
import * as path from 'path';
import * as fs from 'fs';
// ============================================================================
// Module Functions
// ============================================================================
/**
 * Skill level keyword configuration
 */
const SKILL_KEYWORDS = {
    beginner: {
        keywords: [
            'new to', 'first time', 'never used', 'just getting started', 'learning',
            'basics', 'beginner', 'noob', 'what is', 'how do i', 'no experience',
        ],
        weight: 2,
        highThreshold: 2,
    },
    intermediate: {
        keywords: [
            'worked with', 'familiar with', 'experienced', 'built', 'deployed',
            'integration', 'api', 'database', 'ci/cd', 'testing',
        ],
        weight: 1,
        highThreshold: 3,
    },
    advanced: {
        keywords: [
            'production', 'performance optimization', 'cold start', 'concurrent execution',
            'distributed', 'scaling', 'advanced', 'expert', 'complex architecture',
            'migration', 'multi-region', 'enterprise', 'vpc', 'reserved capacity',
        ],
        weight: 3,
        highThreshold: 6,
    },
};
/**
 * Detect user skill level from natural language input
 *
 * Analyzes keywords and patterns to determine if user is beginner/intermediate/advanced
 * @param userInput - User's description of their experience
 * @returns SkillDetectionResult with detected level and confidence
 */
export function detectSkillLevel(userInput) {
    const input = userInput.toLowerCase();
    const signals = [];
    const scores = { beginner: 0, intermediate: 0, advanced: 0 };
    // Calculate scores for each skill level
    for (const [level, config] of Object.entries(SKILL_KEYWORDS)) {
        for (const keyword of config.keywords) {
            if (input.includes(keyword)) {
                scores[level] += config.weight;
                signals.push(`${level.charAt(0).toUpperCase() + level.slice(1)} keyword: "${keyword}"`);
            }
        }
    }
    // Determine skill level based on highest score
    const entries = Object.entries(scores);
    entries.sort((a, b) => b[1] - a[1]);
    const [topLevel, topScore] = entries[0];
    const secondScore = entries[1][1];
    // Default to beginner if no clear signals
    const skillLevel = topScore > secondScore ? topLevel : 'beginner';
    const config = SKILL_KEYWORDS[skillLevel];
    // Determine confidence
    let confidence = 'medium';
    if (userInput.length < 20) {
        confidence = 'low';
    }
    else if (scores[skillLevel] >= config.highThreshold) {
        confidence = 'high';
    }
    else if (skillLevel === 'beginner' && scores.beginner < 2) {
        confidence = 'low';
    }
    return {
        skillLevel,
        confidence,
        signals,
        justification: `Detected ${scores[skillLevel]} ${skillLevel} signals`,
    };
}
/**
 * Load learning paths knowledge base from JSON file
 * @returns Parsed knowledge base
 */
function loadKnowledgeBase() {
    const knowledgeBasePath = path.join(__dirname, '../../..', 'plugins/specweave/knowledge-base/serverless/learning-paths.json');
    if (!fs.existsSync(knowledgeBasePath)) {
        throw new Error(`Learning paths knowledge base not found at ${knowledgeBasePath}`);
    }
    const jsonContent = fs.readFileSync(knowledgeBasePath, 'utf-8');
    return JSON.parse(jsonContent);
}
/**
 * Check if data is fresh (verified within max stale days)
 * @param lastVerified - Date in YYYY-MM-DD format
 * @param maxStaleDays - Maximum days allowed before data is considered stale
 * @returns DataFreshness object
 */
function checkDataFreshness(lastVerified, maxStaleDays = 60) {
    const verifiedDate = new Date(lastVerified);
    const today = new Date();
    const diffTime = Math.abs(today.getTime() - verifiedDate.getTime());
    const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
    return {
        lastVerified,
        isStale: diffDays > maxStaleDays,
        staleDays: diffDays,
        maxStaleDays,
    };
}
/**
 * Recommend learning path for a specific platform and skill level
 *
 * @param platformId - ID of the serverless platform
 * @param skillLevel - Optional skill level (will default to 'beginner' if not provided)
 * @returns Complete learning path recommendation
 */
export function recommendLearningPath(platformId, skillLevel) {
    const knowledgeBase = loadKnowledgeBase();
    // Find platform in knowledge base
    const platformData = knowledgeBase.platforms[platformId];
    if (!platformData) {
        throw new Error(`Platform '${platformId}' not found. Available platforms: ${Object.keys(knowledgeBase.platforms).join(', ')}`);
    }
    // Default to beginner if not specified
    const detectedSkillLevel = skillLevel || 'beginner';
    // Filter resources by skill level
    const tutorials = platformData.resources.tutorials.filter((r) => r.skillLevel === detectedSkillLevel || r.skillLevel === 'beginner');
    const documentation = platformData.resources.documentation.filter((r) => r.skillLevel === detectedSkillLevel || r.skillLevel === 'beginner');
    const videos = platformData.resources.videos.filter((r) => r.skillLevel === detectedSkillLevel || r.skillLevel === 'beginner');
    const courses = platformData.resources.courses.filter((r) => r.skillLevel === detectedSkillLevel || r.skillLevel === 'beginner');
    const sampleProjects = platformData.resources.sampleProjects.filter((r) => r.skillLevel === detectedSkillLevel);
    // Filter best practices by relevance to skill level
    const bestPractices = platformData.bestPractices;
    // Filter pitfalls by skill level relevance
    const commonPitfalls = platformData.commonPitfalls.filter((p) => {
        if (!p.affectedSkillLevels) {
            return true; // Include if not restricted
        }
        return p.affectedSkillLevels.includes(detectedSkillLevel);
    });
    // Check data freshness
    const dataFreshness = checkDataFreshness(platformData.lastVerified, knowledgeBase.maxStaleDays);
    // Generate next steps based on skill level
    const nextSteps = generateNextSteps(detectedSkillLevel, tutorials, sampleProjects);
    // Estimate total learning time
    const estimatedLearningTime = estimateTotalLearningTime(tutorials, videos, courses, sampleProjects);
    return {
        platform: platformData.name,
        platformId,
        skillLevel: detectedSkillLevel,
        tutorials,
        documentation,
        videos,
        courses,
        sampleProjects,
        bestPractices,
        commonPitfalls,
        dataFreshness,
        nextSteps,
        estimatedLearningTime,
    };
}
/**
 * Generate recommended next steps based on skill level
 */
function generateNextSteps(skillLevel, tutorials, projects) {
    const steps = [];
    if (skillLevel === 'beginner') {
        steps.push('Start with the official documentation to understand core concepts');
        steps.push('Complete a beginner tutorial to set up your first function');
        steps.push('Build a simple "Hello World" function to test the basics');
        steps.push('Explore the sample projects for inspiration');
        steps.push('Gradually move to intermediate tutorials as you gain confidence');
    }
    else if (skillLevel === 'intermediate') {
        steps.push('Review the best practices guide for performance and security');
        steps.push('Build a sample project with real-world features (database, API calls)');
        steps.push('Study common pitfalls and how to avoid them');
        steps.push('Explore monitoring and logging strategies');
        steps.push('Consider advanced topics like cold start optimization');
    }
    else {
        steps.push('Review the cost optimization and advanced architecture guides');
        steps.push('Implement advanced patterns (event sourcing, CQRS)');
        steps.push('Work on scaling and multi-region deployments');
        steps.push('Contribute to open-source serverless projects');
        steps.push('Mentor junior developers and share your knowledge');
    }
    return steps;
}
/**
 * Estimate total learning time from resources
 */
function estimateTotalLearningTime(tutorials, videos, courses, projects) {
    const timeEstimates = [];
    // Parse time estimates
    const parseTimeEstimate = (timeStr) => {
        if (!timeStr)
            return null;
        const match = timeStr.match(/(\d+)/);
        if (!match)
            return null;
        const minutes = parseInt(match[1], 10);
        return minutes;
    };
    // Collect all time estimates
    for (const resource of [...tutorials, ...videos, ...courses, ...projects]) {
        const estimate = parseTimeEstimate(resource.estimatedTime);
        if (estimate) {
            timeEstimates.push(estimate);
        }
    }
    if (timeEstimates.length === 0) {
        return undefined;
    }
    const totalMinutes = timeEstimates.reduce((a, b) => a + b, 0);
    const totalHours = Math.round(totalMinutes / 60);
    if (totalHours < 1) {
        return `${totalMinutes} minutes`;
    }
    else if (totalHours < 24) {
        return `${totalHours} hours`;
    }
    else {
        const days = Math.round(totalHours / 8);
        return `${days} days (studying ${Math.round(totalHours / days)} hours/day)`;
    }
}
/**
 * Get all available platform IDs
 */
export function getAvailablePlatforms() {
    try {
        const knowledgeBase = loadKnowledgeBase();
        return Object.keys(knowledgeBase.platforms);
    }
    catch {
        return ['aws-lambda', 'azure-functions', 'gcp-functions', 'firebase-functions', 'supabase'];
    }
}
/**
 * Get platforms with fresh data (not stale)
 */
export function getFreshPlatforms(maxStaleDays = 60) {
    const knowledgeBase = loadKnowledgeBase();
    const freshPlatforms = [];
    for (const [platformId, platformData] of Object.entries(knowledgeBase.platforms)) {
        const freshness = checkDataFreshness(platformData.lastVerified, maxStaleDays);
        if (!freshness.isStale) {
            freshPlatforms.push(platformId);
        }
    }
    return freshPlatforms;
}
/**
 * Get stale platforms (data not verified within max days)
 */
export function getStalePlatforms(maxStaleDays = 60) {
    const knowledgeBase = loadKnowledgeBase();
    const stalePlatforms = [];
    for (const [platformId, platformData] of Object.entries(knowledgeBase.platforms)) {
        const freshness = checkDataFreshness(platformData.lastVerified, maxStaleDays);
        if (freshness.isStale) {
            stalePlatforms.push(platformId);
        }
    }
    return stalePlatforms;
}
/**
 * Resource type to property name mapping
 */
const RESOURCE_TYPE_MAP = {
    tutorial: 'tutorials',
    documentation: 'documentation',
    video: 'videos',
    course: 'courses',
    'sample-project': 'sampleProjects',
    'blog-post': null,
    webinar: null,
};
/**
 * Get learning resources for a specific category and platform
 */
export function getResourcesByType(platformId, resourceType, skillLevel) {
    const knowledgeBase = loadKnowledgeBase();
    const platformData = knowledgeBase.platforms[platformId];
    if (!platformData) {
        throw new Error(`Platform '${platformId}' not found`);
    }
    const resourceKey = RESOURCE_TYPE_MAP[resourceType];
    if (!resourceKey) {
        return [];
    }
    let resources = platformData.resources[resourceKey];
    if (skillLevel) {
        resources = resources.filter((r) => r.skillLevel === skillLevel);
    }
    return resources;
}
/**
 * Validate learning path data integrity
 */
export function validateLearningPathData() {
    const errors = [];
    const warnings = [];
    try {
        const knowledgeBase = loadKnowledgeBase();
        // Check for required fields
        for (const [platformId, platformData] of Object.entries(knowledgeBase.platforms)) {
            if (!platformData.name) {
                errors.push(`Platform ${platformId} missing name`);
            }
            if (!platformData.lastVerified) {
                errors.push(`Platform ${platformId} missing lastVerified date`);
            }
            // Check for stale data
            const freshness = checkDataFreshness(platformData.lastVerified, 60);
            if (freshness.isStale) {
                warnings.push(`Platform ${platformId} data is stale (last verified ${freshness.staleDays} days ago)`);
            }
            // Validate all resources have IDs
            const allResources = [
                ...platformData.resources.tutorials,
                ...platformData.resources.documentation,
                ...platformData.resources.videos,
                ...platformData.resources.courses,
                ...platformData.resources.sampleProjects,
            ];
            for (const resource of allResources) {
                if (!resource.id) {
                    errors.push(`Platform ${platformId} has resource without ID: ${resource.title}`);
                }
                if (!resource.url) {
                    errors.push(`Platform ${platformId} resource ${resource.id} missing URL: ${resource.title}`);
                }
            }
        }
    }
    catch (error) {
        errors.push(`Failed to load knowledge base: ${error}`);
    }
    return {
        isValid: errors.length === 0,
        errors,
        warnings,
    };
}
//# sourceMappingURL=learning-path-recommender.js.map