i-self 0.4.3

Personal developer-companion CLI: scans your repos, indexes code semantically, watches your activity, and moves AI-agent sessions between tools (Claude Code, Aider, Goose, OpenAI Codex CLI, Continue.dev, OpenCode).
use crate::skills::{SkillGapAnalyzer, Skill, SkillLevel, GapAnalysis, get_common_job_profiles};
use anyhow::Result;
use clap::Parser;

#[derive(Parser)]
pub struct SkillsCommand {
    #[arg(short, long)]
    pub job: Option<String>,

    #[arg(short, long)]
    pub list_jobs: bool,

    #[arg(short, long)]
    pub add_skill: Option<String>,

    #[arg(short, long)]
    pub level: Option<String>,
}

impl SkillsCommand {
    pub async fn run(&self) -> Result<()> {
        if self.list_jobs {
            println!("\n=== Available Job Profiles ===\n");
            let jobs = get_common_job_profiles();
            for (idx, job) in jobs.iter().enumerate() {
                println!("{}. {}", idx + 1, job.title);
                println!("   Required skills: {}", job.required_skills
                    .iter()
                    .map(|s| s.skill_name.as_str())
                    .collect::<Vec<_>>()
                    .join(", "));
                println!();
            }
            return Ok(());
        }

        let mut analyzer = SkillGapAnalyzer::new();

        let skills = load_current_skills()?;
        analyzer.load_from_profile(skills);

        if let Some(ref job_title) = self.job {
            let jobs = get_common_job_profiles();
            let job = jobs.iter().find(|j| j.title.to_lowercase().contains(&job_title.to_lowercase()));
            
            if let Some(job) = job {
                let analysis = analyzer.analyze_job(job);
                print_gap_analysis(&analysis);
            } else {
                println!("Job profile '{}' not found. Use --list-jobs to see available profiles.", job_title);
            }
            return Ok(());
        }

        println!("\n=== Your Skills ===\n");
        let summary = analyzer.get_skill_summary();
        for (name, skill) in summary {
            println!("{}: {} ({} projects)", name, skill.level.label(), skill.projects_count);
        }

        Ok(())
    }
}

fn load_current_skills() -> Result<Vec<Skill>> {
    let mut skills = Vec::new();

    skills.push(Skill {
        name: "Rust".to_string(),
        level: SkillLevel::Advanced,
        years_experience: Some(3.0),
        last_used: Some("2024-01".to_string()),
        projects_count: 15,
    });

    skills.push(Skill {
        name: "Python".to_string(),
        level: SkillLevel::Advanced,
        years_experience: Some(5.0),
        last_used: Some("2024-01".to_string()),
        projects_count: 25,
    });

    skills.push(Skill {
        name: "JavaScript".to_string(),
        level: SkillLevel::Advanced,
        years_experience: Some(6.0),
        last_used: Some("2024-01".to_string()),
        projects_count: 20,
    });

    skills.push(Skill {
        name: "TypeScript".to_string(),
        level: SkillLevel::Intermediate,
        years_experience: Some(2.0),
        last_used: Some("2024-01".to_string()),
        projects_count: 8,
    });

    skills.push(Skill {
        name: "Docker".to_string(),
        level: SkillLevel::Intermediate,
        years_experience: Some(2.0),
        last_used: Some("2024-01".to_string()),
        projects_count: 10,
    });

    Ok(skills)
}

fn print_gap_analysis(analysis: &GapAnalysis) {
    println!("\n=== Gap Analysis: {} ===\n", analysis.job_title);
    println!("Overall Match: {:.1}%\n", analysis.overall_match_percentage);

    if !analysis.strengths.is_empty() {
        println!("✓ Strengths:");
        for skill in &analysis.strengths {
            println!("  - {}", skill);
        }
        println!();
    }

    if !analysis.gaps.is_empty() {
        println!("⚠ Skill Gaps:");
        for gap in &analysis.gaps {
            let critical = if gap.is_critical { " [CRITICAL]" } else { "" };
            println!("  - {}: {}{}{}", 
                gap.skill_name, 
                gap.current_level.label(), 
                gap.required_level.label(),
                critical);
            println!("    {}", gap.recommendation);
        }
        println!();
    }

    if !analysis.missing_critical_skills.is_empty() {
        println!("✗ Missing Critical Skills:");
        for skill in &analysis.missing_critical_skills {
            println!("  - {}", skill);
        }
        println!();
    }

    if !analysis.recommendations.is_empty() {
        println!("Recommendations:");
        for rec in &analysis.recommendations {
            println!("{}", rec);
        }
    }
}