//! Integration tests for `mcptest skill` (WOR-1270): print the packaged
//! agent skill, install it into a Claude Code layout, and guarantee the
//! installed bytes match the canonical copy under `examples/agent-skill/`.

use std::fs;
use std::path::Path;

use assert_cmd::Command;
use predicates::prelude::*;

fn mcptest() -> Command {
    Command::cargo_bin("mcptest").expect("binary builds")
}

/// The canonical skill body, read from the repo so the test pins the
/// embedded copy to the example rather than to itself.
fn canonical_skill() -> String {
    let path = concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/../../examples/agent-skill/SKILL.md"
    );
    fs::read_to_string(path).expect("canonical SKILL.md is readable")
}

/// The canonical subagent body next to the canonical skill.
fn canonical_subagent() -> String {
    let path = concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/../../examples/agent-skill/test-mcp-server.subagent.md"
    );
    fs::read_to_string(path).expect("canonical subagent file is readable")
}

fn installed_skill_path(base: &Path) -> std::path::PathBuf {
    base.join(".claude/skills/test-mcp-server/SKILL.md")
}

fn installed_subagent_path(base: &Path) -> std::path::PathBuf {
    base.join(".claude/agents/mcp-server-tester.md")
}

#[test]
fn prints_the_skill_to_stdout_without_install() {
    let assertion = mcptest().arg("skill").assert().success();
    let stdout = String::from_utf8(assertion.get_output().stdout.clone()).unwrap();
    assert_eq!(
        stdout,
        canonical_skill(),
        "stdout must be the canonical skill, byte for byte"
    );
}

#[test]
fn install_writes_the_project_level_skill_and_subagent() {
    let dir = tempfile::tempdir().unwrap();
    mcptest()
        .current_dir(dir.path())
        .args(["skill", "--install"])
        .assert()
        .success();
    assert!(
        installed_skill_path(dir.path()).is_file(),
        "skill lands at .claude/skills/test-mcp-server/SKILL.md"
    );
    assert!(
        installed_subagent_path(dir.path()).is_file(),
        "subagent lands at .claude/agents/mcp-server-tester.md"
    );
}

#[test]
fn installed_files_byte_equal_the_canonical_examples() {
    let dir = tempfile::tempdir().unwrap();
    mcptest()
        .current_dir(dir.path())
        .args(["skill", "--install"])
        .assert()
        .success();
    let skill = fs::read_to_string(installed_skill_path(dir.path())).unwrap();
    let subagent = fs::read_to_string(installed_subagent_path(dir.path())).unwrap();
    assert_eq!(
        skill,
        canonical_skill(),
        "installed SKILL.md drifted from examples/agent-skill/SKILL.md"
    );
    assert_eq!(
        subagent,
        canonical_subagent(),
        "installed subagent drifted from examples/agent-skill/test-mcp-server.subagent.md"
    );
}

#[test]
fn install_success_line_includes_the_pairing_hint() {
    let dir = tempfile::tempdir().unwrap();
    mcptest()
        .current_dir(dir.path())
        .args(["skill", "--install"])
        .assert()
        .success()
        .stdout(predicate::str::contains(
            "Installed. Pair with: mcptest mcp-server --install --enable-writes",
        ));
}

#[test]
fn install_refuses_an_existing_skill_without_force() {
    let dir = tempfile::tempdir().unwrap();
    let existing = installed_skill_path(dir.path());
    fs::create_dir_all(existing.parent().unwrap()).unwrap();
    fs::write(&existing, "hand-edited").unwrap();
    mcptest()
        .current_dir(dir.path())
        .args(["skill", "--install"])
        .assert()
        .code(2)
        .stderr(predicate::str::contains("refusing to overwrite"))
        .stderr(predicate::str::contains("--force"));
    assert_eq!(
        fs::read_to_string(&existing).unwrap(),
        "hand-edited",
        "a refused install must leave the existing file untouched"
    );
}

#[test]
fn force_overwrites_an_existing_install() {
    let dir = tempfile::tempdir().unwrap();
    let existing = installed_skill_path(dir.path());
    fs::create_dir_all(existing.parent().unwrap()).unwrap();
    fs::write(&existing, "stale").unwrap();
    mcptest()
        .current_dir(dir.path())
        .args(["skill", "--install", "--force"])
        .assert()
        .success();
    assert_eq!(
        fs::read_to_string(&existing).unwrap(),
        canonical_skill(),
        "--force replaces the stale copy with the bundled skill"
    );
}

#[test]
fn dir_override_installs_under_the_given_base() {
    let dir = tempfile::tempdir().unwrap();
    let base = dir.path().join("custom");
    mcptest()
        .current_dir(dir.path())
        .args(["skill", "--install", "--dir", base.to_str().unwrap()])
        .assert()
        .success();
    assert!(base.join("skills/test-mcp-server/SKILL.md").is_file());
    assert!(base.join("agents/mcp-server-tester.md").is_file());
    assert!(
        !dir.path().join(".claude").exists(),
        "--dir must fully replace the .claude base"
    );
}

#[cfg(unix)]
#[test]
fn global_installs_under_the_home_claude_dir() {
    let home = tempfile::tempdir().unwrap();
    mcptest()
        .env("HOME", home.path())
        .args(["skill", "--install", "--global"])
        .assert()
        .success();
    assert!(installed_skill_path(home.path()).is_file());
    assert!(installed_subagent_path(home.path()).is_file());
}

#[test]
fn install_flags_require_install() {
    for flag in ["--force", "--global"] {
        mcptest().args(["skill", flag]).assert().code(2);
    }
}
