use robson_plugin_implementation_workflow::scan_for_misplaced_tests;
use std::fs;

// --- scan_for_misplaced_tests: clean cases ---

#[test]
fn test_no_violations_when_tests_are_in_crate_tests_dir() {
    let tmp = tempfile::tempdir().unwrap();
    let crate_dir = tmp.path().join("my-crate");
    let tests_dir = crate_dir.join("tests");
    fs::create_dir_all(&tests_dir).unwrap();
    // Cargo.toml makes this a valid crate-level tests/
    fs::write(
        crate_dir.join("Cargo.toml"),
        "[package]\nname = \"my-crate\"",
    )
    .unwrap();
    fs::write(
        tests_dir.join("my_tests.rs"),
        "#[test]\nfn it_works() { assert!(true); }",
    )
    .unwrap();

    let violations = scan_for_misplaced_tests(tmp.path());
    assert!(
        violations.is_empty(),
        "tests in crate tests/ should not be flagged"
    );
}

#[test]
fn test_no_violations_when_src_has_no_test_markers() {
    let tmp = tempfile::tempdir().unwrap();
    let src_dir = tmp.path().join("my-crate").join("src");
    fs::create_dir_all(&src_dir).unwrap();
    fs::write(
        src_dir.join("lib.rs"),
        "pub fn add(a: i32, b: i32) -> i32 { a + b }",
    )
    .unwrap();

    let violations = scan_for_misplaced_tests(tmp.path());
    assert!(
        violations.is_empty(),
        "clean src/ should produce no violations"
    );
}

#[test]
fn test_no_violations_on_empty_repo() {
    let tmp = tempfile::tempdir().unwrap();
    let violations = scan_for_misplaced_tests(tmp.path());
    assert!(violations.is_empty());
}

// --- scan_for_misplaced_tests: violation cases ---

#[test]
fn test_detects_test_attr_in_src_file() {
    let tmp = tempfile::tempdir().unwrap();
    let src_dir = tmp.path().join("my-crate").join("src");
    fs::create_dir_all(&src_dir).unwrap();
    let lib_rs = src_dir.join("lib.rs");
    fs::write(
        &lib_rs,
        "pub fn add(a: i32, b: i32) -> i32 { a + b }\n\n#[test]\nfn test_add() { assert_eq!(add(1, 2), 3); }",
    )
    .unwrap();

    let violations = scan_for_misplaced_tests(tmp.path());
    assert_eq!(violations.len(), 1);
    assert_eq!(violations[0], lib_rs);
}

#[test]
fn test_detects_cfg_test_in_src_file() {
    let tmp = tempfile::tempdir().unwrap();
    let src_dir = tmp.path().join("crate-a").join("src");
    fs::create_dir_all(&src_dir).unwrap();
    let path = src_dir.join("utils.rs");
    fs::write(
        &path,
        "#[cfg(test)]\nmod tests {\n    #[test]\n    fn it_works() {}\n}",
    )
    .unwrap();

    let violations = scan_for_misplaced_tests(tmp.path());
    assert_eq!(violations.len(), 1);
    assert_eq!(violations[0], path);
}

#[test]
fn test_detects_multiple_violations_across_crates() {
    let tmp = tempfile::tempdir().unwrap();
    for crate_name in &["crate-a", "crate-b"] {
        let src_dir = tmp.path().join(crate_name).join("src");
        fs::create_dir_all(&src_dir).unwrap();
        fs::write(src_dir.join("lib.rs"), "#[test]\nfn test_something() {}").unwrap();
    }

    let mut violations = scan_for_misplaced_tests(tmp.path());
    violations.sort();
    assert_eq!(violations.len(), 2, "both crates should report violations");
}

#[test]
fn test_workspace_root_tests_dir_is_flagged() {
    let tmp = tempfile::tempdir().unwrap();
    // Workspace root has no Cargo.toml sibling → tests/ is NOT a valid crate tests dir
    let root_tests = tmp.path().join("tests");
    fs::create_dir_all(&root_tests).unwrap();
    let test_file = root_tests.join("integration.rs");
    fs::write(&test_file, "#[test]\nfn root_test() {}").unwrap();

    let violations = scan_for_misplaced_tests(tmp.path());
    assert_eq!(
        violations.len(),
        1,
        "workspace-root tests/ should be flagged"
    );
    assert_eq!(violations[0], test_file);
}

// --- compose_test_correction_prompt ---

#[test]
fn test_correction_prompt_mentions_tests_folder() {
    use robson_connector_claude::compose_test_correction_prompt;
    let prompt = compose_test_correction_prompt();
    assert!(
        prompt.contains("tests/"),
        "prompt should reference the tests/ folder"
    );
}

#[test]
fn test_correction_prompt_mentions_test_attribute() {
    use robson_connector_claude::compose_test_correction_prompt;
    let prompt = compose_test_correction_prompt();
    assert!(
        prompt.contains("#[test]") || prompt.contains("test"),
        "prompt should reference test attributes"
    );
}

// --- target/ and hidden dirs are ignored ---

#[test]
fn test_target_dir_is_skipped() {
    let tmp = tempfile::tempdir().unwrap();
    let target_src = tmp.path().join("target").join("debug").join("build");
    fs::create_dir_all(&target_src).unwrap();
    fs::write(
        target_src.join("generated.rs"),
        "#[test]\nfn generated() {}",
    )
    .unwrap();

    let violations = scan_for_misplaced_tests(tmp.path());
    assert!(violations.is_empty(), "target/ should be skipped");
}

#[test]
fn test_hidden_dirs_are_skipped() {
    let tmp = tempfile::tempdir().unwrap();
    let hidden = tmp.path().join(".hidden").join("src");
    fs::create_dir_all(&hidden).unwrap();
    fs::write(hidden.join("mod.rs"), "#[test]\nfn hidden_test() {}").unwrap();

    let violations = scan_for_misplaced_tests(tmp.path());
    assert!(violations.is_empty(), "hidden dirs should be skipped");
}

// --- unicode in file paths / content ---

#[test]
fn test_unicode_content_in_src_file_detected() {
    let tmp = tempfile::tempdir().unwrap();
    let src_dir = tmp.path().join("meu-crate").join("src");
    fs::create_dir_all(&src_dir).unwrap();
    let path = src_dir.join("lib.rs");
    // Description in Portuguese + test marker
    fs::write(
        &path,
        "// Implementação de somas\n#[test]\nfn testa_soma() {}",
    )
    .unwrap();

    let violations = scan_for_misplaced_tests(tmp.path());
    assert_eq!(violations.len(), 1);
}
