/// AI provider skill installer.
///
/// Installs a Claude Code skill file (`SKILL.md`) that teaches the AI
/// provider how to invoke the `km` CLI for code analysis. The skill
/// can be installed at project level (`.claude/skills/`) or user level
/// (`~/.claude/skills/`). With `--with-permissions`, also configures
/// bash permissions so `km` commands run without prompting.
use std::fs;
use std::io::{self, Write};
use std::path::PathBuf;

/// Skill markdown content embedded at compile time.
/// Describes all available `km` subcommands and their JSON schemas.
const SKILL_CONTENT: &str = r#"---
name: km-analyze
description: Analyze a code repository using km (code metrics) tool
---

# km — Code Metrics Analysis Skill

You have access to the `km` CLI tool for comprehensive code analysis. Use it to analyze repositories across multiple dimensions.

## Available Commands

Run these via the Bash tool. Always use `--json` for machine-readable output.

### Lines of Code
```bash
km loc [PATH] --json
```
Language breakdown: files, blank lines, comment lines, code lines.

### Code Health Score
```bash
km score [PATH] --json
km score [PATH] --json --model legacy
```
Overall grade (A++ to F--). Default model (cogcom): 5 dimensions — cognitive complexity, duplication, indentation, Halstead effort, file size. Legacy model (--model legacy): 6 dimensions — MI, cyclomatic complexity, duplication, indentation, Halstead effort, file size.

### Score Diff (requires git)
```bash
km score diff [PATH] --json --git-ref HEAD~1
```
Compare current code health score against a git ref. Shows per-dimension deltas.

### Cognitive Complexity
```bash
km cogcom [PATH] --json --top 20
```
SonarSource method (2017). Measures how difficult code is to understand, penalizing deep nesting.

### Cyclomatic Complexity
```bash
km cycom [PATH] --json --top 20
```
Per-file and per-function complexity. High values indicate hard-to-test code.

### Maintainability Index
```bash
km miv [PATH] --json --top 20
```
Verifysoft variant (with comment weight). Values below 65 are hard to maintain.

### Halstead Complexity
```bash
km hal [PATH] --json --top 20 --sort-by effort
```
Effort, volume, and estimated bugs per file.

### Indentation Complexity
```bash
km indent [PATH] --json
```
Indentation depth stddev — high values suggest deeply nested code.

### Duplicate Code
```bash
km dups [PATH] --json --report
```
Duplicate blocks across the project.

### Hotspots (requires git)
```bash
km hotspots [PATH] --json --top 20
```
Files that change frequently AND have high complexity — top refactoring targets.

### Code Ownership (requires git)
```bash
km knowledge [PATH] --json --top 20
```
Bus factor risk per file via git blame analysis.

### Temporal Coupling (requires git)
```bash
km tc [PATH] --json --top 20
```
Files that change together in commits — hidden dependencies.

## Analysis Workflow

1. Start with `km score` for the overall health grade
2. Run `km loc` for project size and language breakdown
3. Use `km cogcom`, `km cycom` and `km miv` to find the most complex/unmaintainable files
4. Run `km hotspots` to find high-risk change-prone files
5. Check `km dups` for code duplication opportunities
6. Optionally run `km knowledge` and `km tc` for team/architecture insights
7. Use `km score diff --git-ref HEAD~N` to track score changes over time

## Output Format

Produce a structured report with:
- **Overview**: Project size, languages, overall grade
- **Code Health**: Score breakdown by dimension
- **Complexity Hotspots**: Worst files by complexity
- **Maintainability**: Files hardest to maintain
- **Key Findings**: Notable patterns and risks
- **Recommendations**: Prioritized, actionable suggestions

Reference specific file names and metric values. Be concise but thorough.
"#;

/// Install the `km-analyze` skill for the given AI provider.
///
/// Prompts the user to choose between project-level and user-level
/// installation, creates the directory structure, and writes the skill file.
/// Currently only the `claude` provider is supported.
pub fn install(provider: &str, with_permissions: bool) -> Result<(), Box<dyn std::error::Error>> {
    if provider != "claude" {
        return Err(format!("Unsupported provider: {provider}. Supported: claude").into());
    }

    println!("Where do you want to install the km skill?");
    println!("  1) Project-level (.claude/skills/km-analyze/)");
    println!("  2) User-level (~/.claude/skills/km-analyze/)");
    print!("Choose [1/2]: ");
    io::stdout().flush()?;

    let mut choice = String::new();
    io::stdin().read_line(&mut choice)?;
    let choice = choice.trim();

    let (skill_dir, project_root) = match choice {
        "1" => {
            // Find the git repo root so the skill is installed at the project root
            // even when invoked from a subdirectory.
            let repo = git2::Repository::discover(".")
                .map_err(|_| "Could not find a git repository. Run from a project directory or use option 2 (user-level).")?;
            let workdir = repo
                .workdir()
                .ok_or("Could not determine repository working directory")?;
            (
                workdir.join(".claude/skills/km-analyze"),
                Some(workdir.to_path_buf()),
            )
        }
        "2" => {
            let home = std::env::var("HOME").map_err(|_| "Could not determine home directory")?;
            (PathBuf::from(home).join(".claude/skills/km-analyze"), None)
        }
        _ => return Err("Invalid choice. Please enter 1 or 2.".into()),
    };

    fs::create_dir_all(&skill_dir)?;
    let skill_path = skill_dir.join("SKILL.md");
    fs::write(&skill_path, SKILL_CONTENT)?;

    println!("Skill installed at: {}", skill_path.display());
    println!("Claude Code will now be able to use km for code analysis.");

    if with_permissions {
        if let Some(root) = project_root {
            super::permissions::install(&root)?;
        } else {
            eprintln!(
                "warning: --with-permissions only applies to project-level installs, skipping"
            );
        }
    }

    Ok(())
}
