use crate::learning::{LearningPathGenerator, LearningPlan};
use crate::skills::{SkillGapAnalyzer, Skill, SkillLevel, get_common_job_profiles};
use anyhow::Result;
use clap::Parser;
#[derive(Parser)]
pub struct LearningCommand {
#[arg(short, long)]
pub job: Option<String>,
#[arg(short, long)]
pub skill: Option<String>,
#[arg(short, long)]
pub target_level: Option<String>,
}
impl LearningCommand {
pub async fn run(&self) -> Result<()> {
let mut analyzer = SkillGapAnalyzer::new();
let skills = load_current_skills()?;
analyzer.load_from_profile(skills);
let gaps = 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);
analysis.gaps
} else {
println!("Job profile '{}' not found.", job_title);
return Ok(());
}
} else if let Some(ref skill_name) = self.skill {
let skill_key = skill_name.to_lowercase();
if let Some(skill) = analyzer.current_skills.get(&skill_key) {
let target = self.target_level
.as_ref()
.and_then(|l| match l.to_lowercase().as_str() {
"beginner" => Some(SkillLevel::Beginner),
"intermediate" => Some(SkillLevel::Intermediate),
"advanced" => Some(SkillLevel::Advanced),
"expert" => Some(SkillLevel::Expert),
"master" => Some(SkillLevel::Master),
_ => None,
})
.unwrap_or(SkillLevel::Advanced);
vec![crate::skills::SkillGap {
skill_name: skill_name.clone(),
current_level: skill.level,
required_level: target,
gap_score: target.to_score() as i32 - skill.level.to_score() as i32,
is_critical: true,
recommendation: format!("Learn {} to {} level", skill_name, target.label()),
}]
} else {
println!("Skill '{}' not found in your profile.", skill_name);
return Ok(());
}
} else {
println!("Please specify --job or --skill");
return Ok(());
};
let plan = LearningPathGenerator::generate_plan(&gaps, &analyzer.current_skills);
print_learning_plan(&plan);
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_learning_plan(plan: &LearningPlan) {
println!("\n=== Learning Plan ===\n");
println!("Total Estimated Time: {:.1} hours", plan.total_estimated_hours);
println!("Focus Areas: {}\n", plan.focus_areas.join(", "));
for (idx, rec) in plan.recommendations.iter().enumerate() {
let priority_label = match rec.priority {
1 => "🔴 High",
2 => "🟡 Medium",
_ => "🟢 Low",
};
println!("{}. {} [{}]", idx + 1, rec.skill_name, priority_label);
println!(" Current: {} → Target: {}", rec.current_level, rec.target_level);
println!(" Reason: {}", rec.reason);
if let Some(ref path) = rec.path {
println!(" Estimated Time: {:.1} hours", path.estimated_total_hours);
println!(" Resources:");
for (ridx, resource) in path.resources.iter().enumerate() {
println!(" {}. {} ({})", ridx + 1, resource.title, resource.difficulty);
println!(" {}", resource.url);
}
}
println!();
}
}