use mad_hatter::file_summary::{FileSummary, FileSummaryResult};

// --- Tests moved from engine/src/external/skeleton.rs ---

#[test]
fn test_load() {
    let fs = FileSummary::get();
    // Just verify it loads without panic and has expected languages
    let _ = fs.extract("test.rs", "fn main() {}");
}

#[test]
fn test_extract_rust() {
    let fs = FileSummary::get();
    match fs.extract("main.rs", "use std::io;\n\npub fn hello() {\n    println!(\"hi\");\n}\n\nstruct Foo;") {
        FileSummaryResult::Skeleton(s) => {
            assert!(s.contains("pub fn hello"));
            assert!(s.contains("struct Foo"));
        }
        other => panic!("Expected Skeleton, got {:?}", variant_name(&other)),
    }
}

#[test]
fn test_unknown_ext_returns_preview() {
    let fs = FileSummary::get();
    match fs.extract("data.xyz", "line1\nline2\nline3") {
        FileSummaryResult::Preview(s) => {
            assert!(s.contains("line1"));
            assert!(s.contains("line2"));
            assert!(s.contains("line3"));
        }
        other => panic!("Expected Preview, got {:?}", variant_name(&other)),
    }
}

#[test]
fn test_extract_md_returns_full() {
    let fs = FileSummary::get();
    assert!(matches!(
        fs.extract("readme.md", "# Hello"),
        FileSummaryResult::Full
    ));
}

#[test]
fn test_extract_rust_from_path() {
    let fs = FileSummary::get();
    match fs.extract("src/main.rs", "pub fn main() {}") {
        FileSummaryResult::Skeleton(s) => {
            assert!(s.contains("pub fn main"));
        }
        other => panic!("Expected Skeleton, got {:?}", variant_name(&other)),
    }
}

#[test]
fn test_extract_unknown_from_path() {
    let fs = FileSummary::get();
    assert!(matches!(
        fs.extract("data.xyz", "anything"),
        FileSummaryResult::Preview(_)
    ));
}

// --- Preview tests ---

#[test]
fn test_preview_short_file_no_truncation() {
    let fs = FileSummary::get();
    // 10 lines — under threshold (15), should show all with line numbers
    let content = (1..=10).map(|i| format!("line {}", i)).collect::<Vec<_>>().join("\n");
    match fs.extract("data.xyz", &content) {
        FileSummaryResult::Preview(s) => {
            assert!(s.contains("   1: line 1"));
            assert!(s.contains("  10: line 10"));
            assert!(!s.contains("..."));
        }
        other => panic!("Expected Preview, got {:?}", variant_name(&other)),
    }
}

#[test]
fn test_preview_medium_file_shows_all() {
    let fs = FileSummary::get();
    // 12 lines — between HEAD(10) and THRESHOLD(15), shows all lines
    let content = (1..=12).map(|i| format!("line {}", i)).collect::<Vec<_>>().join("\n");
    match fs.extract("data.xyz", &content) {
        FileSummaryResult::Preview(s) => {
            assert!(s.contains("   1: line 1"));
            assert!(s.contains("  12: line 12"));
            assert!(!s.contains("..."));
        }
        other => panic!("Expected Preview, got {:?}", variant_name(&other)),
    }
}

#[test]
fn test_preview_long_file_truncated() {
    let fs = FileSummary::get();
    // 20 lines — over threshold, should show head 10 + ellipsis + tail 5
    let content = (1..=20).map(|i| format!("line {}", i)).collect::<Vec<_>>().join("\n");
    match fs.extract("data.xyz", &content) {
        FileSummaryResult::Preview(s) => {
            // Head: lines 1-10
            assert!(s.contains("   1: line 1"));
            assert!(s.contains("  10: line 10"));
            // Ellipsis
            assert!(s.contains("..."));
            // Tail: lines 16-20
            assert!(s.contains("  16: line 16"));
            assert!(s.contains("  20: line 20"));
            // Middle should not be present
            assert!(!s.contains("line 11"));
            assert!(!s.contains("line 15"));
        }
        other => panic!("Expected Preview, got {:?}", variant_name(&other)),
    }
}

#[test]
fn test_preview_exactly_threshold() {
    let fs = FileSummary::get();
    // 15 lines — exactly threshold, should show all (no ellipsis)
    let content = (1..=15).map(|i| format!("line {}", i)).collect::<Vec<_>>().join("\n");
    match fs.extract("data.xyz", &content) {
        FileSummaryResult::Preview(s) => {
            assert!(s.contains("   1: line 1"));
            assert!(s.contains("  15: line 15"));
            assert!(!s.contains("..."));
        }
        other => panic!("Expected Preview, got {:?}", variant_name(&other)),
    }
}

#[test]
fn test_preview_just_over_threshold() {
    let fs = FileSummary::get();
    // 16 lines — just over threshold, head 10 + ellipsis + tail 5 (lines 12-16)
    let content = (1..=16).map(|i| format!("line {}", i)).collect::<Vec<_>>().join("\n");
    match fs.extract("data.xyz", &content) {
        FileSummaryResult::Preview(s) => {
            assert!(s.contains("   1: line 1"));
            assert!(s.contains("  10: line 10"));
            assert!(s.contains("..."));
            assert!(s.contains("  12: line 12"));
            assert!(s.contains("  16: line 16"));
            assert!(!s.contains(": line 11"));
        }
        other => panic!("Expected Preview, got {:?}", variant_name(&other)),
    }
}

#[test]
fn test_skeleton_python() {
    let fs = FileSummary::get();
    let content = "import os\n\ndef hello():\n    pass\n\nclass Foo:\n    pass\n";
    match fs.extract("app.py", content) {
        FileSummaryResult::Skeleton(s) => {
            assert!(s.contains("def hello"));
            assert!(s.contains("class Foo"));
        }
        other => panic!("Expected Skeleton, got {:?}", variant_name(&other)),
    }
}

#[test]
fn test_skeleton_empty_content_returns_preview() {
    let fs = FileSummary::get();
    // Rust file but no skeleton markers match → empty skeleton → falls through to Preview
    match fs.extract("main.rs", "let x = 1;\nlet y = 2;\n") {
        FileSummaryResult::Preview(_) => {} // OK: no skeleton lines matched
        FileSummaryResult::Skeleton(s) if s.is_empty() => {} // Also OK
        other => panic!("Expected Preview or empty Skeleton, got {:?}", variant_name(&other)),
    }
}

#[test]
fn test_full_extensions_case_insensitive() {
    let fs = FileSummary::get();
    assert!(matches!(fs.extract("README.MD", "# Hello"), FileSummaryResult::Full));
}

fn variant_name(r: &FileSummaryResult) -> &'static str {
    match r {
        FileSummaryResult::Full => "Full",
        FileSummaryResult::Skeleton(_) => "Skeleton",
        FileSummaryResult::Preview(_) => "Preview",
    }
}