//! Tests for LSP hover functionality
//!
//! This module tests hover information display for:
//! - Keywords (character, template, behavior, etc.)
//! - Type information for symbols
//! - Documentation display
//! - Edge cases (whitespace, EOF, invalid positions)

use tower_lsp::lsp_types::{
    HoverContents,
    MarkupContent,
    MarkupKind,
};

use super::hover::get_hover_info;

#[test]
fn test_hover_on_character_keyword() {
    let source = "character Alice { age: 7 }";

    // Hover over "character" keyword at position 0,5 (middle of "character")
    let hover = get_hover_info(source, 0, 5);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { kind, value }) => {
            assert_eq!(kind, MarkupKind::Markdown);
            assert!(value.contains("character"));
            assert!(value.contains("Defines a character entity"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_on_template_keyword() {
    let source = "template Person { name: String }";

    let hover = get_hover_info(source, 0, 4);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { value, .. }) => {
            assert!(value.contains("template"));
            assert!(value.contains("reusable field template"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_on_behavior_keyword() {
    let source = "behavior WalkAround { walk_to_garden }";

    let hover = get_hover_info(source, 0, 4);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { value, .. }) => {
            assert!(value.contains("behavior"));
            assert!(value.contains("behavior tree"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_on_life_arc_keyword() {
    let source = "life_arc Growth { state child { } }";

    let hover = get_hover_info(source, 0, 5);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { value, .. }) => {
            assert!(value.contains("life_arc"));
            assert!(value.contains("state machine"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_on_schedule_keyword() {
    let source = "schedule Daily { 08:00-12:00 work }";

    let hover = get_hover_info(source, 0, 4);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { value, .. }) => {
            assert!(value.contains("schedule"));
            assert!(value.contains("daily schedule"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_on_institution_keyword() {
    let source = "institution Bakery { location: wonderland }";

    let hover = get_hover_info(source, 0, 6);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { value, .. }) => {
            assert!(value.contains("institution"));
            assert!(value.contains("organization"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_on_relationship_keyword() {
    let source = "relationship Friendship { participants: [Alice, Bob] }";

    let hover = get_hover_info(source, 0, 8);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { value, .. }) => {
            assert!(value.contains("relationship"));
            assert!(value.contains("multi-party"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_on_location_keyword() {
    let source = "location Garden { description: \"A beautiful garden\" }";

    let hover = get_hover_info(source, 0, 4);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { value, .. }) => {
            assert!(value.contains("location"));
            assert!(value.contains("place"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_on_species_keyword() {
    let source = "species Human { include CommonTraits }";

    let hover = get_hover_info(source, 0, 4);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { value, .. }) => {
            assert!(value.contains("species"));
            assert!(value.contains("templates"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_on_use_keyword() {
    let source = "use characters::Alice;";

    let hover = get_hover_info(source, 0, 1);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { value, .. }) => {
            assert!(value.contains("use"));
            assert!(value.contains("Imports"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_on_from_keyword() {
    let source = "character Alice from Person { }";

    let hover = get_hover_info(source, 0, 17);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { value, .. }) => {
            assert!(value.contains("from"));
            assert!(value.contains("templates"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_on_state_keyword() {
    let source = "life_arc Growth { state child { } }";

    let hover = get_hover_info(source, 0, 19);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { value, .. }) => {
            assert!(value.contains("state"));
            assert!(value.contains("life arc"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_on_whitespace_returns_none() {
    let source = "character Alice { age: 7 }";

    // Hover over whitespace between "character" and "Alice"
    let hover = get_hover_info(source, 0, 10);

    assert!(hover.is_none(), "Hovering on whitespace should return None");
}

#[test]
fn test_hover_on_unknown_word_returns_none() {
    let source = "character Alice { age: 7 }";

    // Hover over "Alice" (not a keyword)
    let hover = get_hover_info(source, 0, 12);

    assert!(
        hover.is_none(),
        "Hovering on non-keyword should return None"
    );
}

#[test]
fn test_hover_at_eof_returns_none() {
    let source = "character Alice { age: 7 }";

    // Try to hover beyond the line
    let hover = get_hover_info(source, 0, 100);

    assert!(hover.is_none(), "Hovering beyond line should return None");
}

#[test]
fn test_hover_on_invalid_line_returns_none() {
    let source = "character Alice { age: 7 }";

    // Try to hover on a line that doesn't exist
    let hover = get_hover_info(source, 100, 0);

    assert!(
        hover.is_none(),
        "Hovering on invalid line should return None"
    );
}

#[test]
fn test_hover_on_comment_returns_none() {
    let source = "// This is a comment\ncharacter Alice { }";

    // Hover over the comment
    let hover = get_hover_info(source, 0, 5);

    // Comments don't contain keywords, so this should return None
    assert!(hover.is_none(), "Hovering on comment should return None");
}

#[test]
fn test_hover_multiline_document() {
    let source = r#"
character Alice { age: 7 }
template Person { name: String }
behavior Walk { walk_around }
"#;

    // Hover on "template" keyword on line 2
    let hover = get_hover_info(source, 2, 4);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { value, .. }) => {
            assert!(value.contains("template"));
        },
        | _ => panic!("Expected markup content"),
    }
}

#[test]
fn test_hover_preserves_markdown_formatting() {
    let source = "character Alice { }";

    let hover = get_hover_info(source, 0, 5);

    assert!(hover.is_some());
    let hover = hover.unwrap();

    match hover.contents {
        | HoverContents::Markup(MarkupContent { kind, value }) => {
            assert_eq!(kind, MarkupKind::Markdown);
            // Check for markdown formatting
            assert!(value.contains("**character**") || value.contains("character"));
            assert!(value.contains("`character Name { ... }`") || value.contains("Syntax"));
        },
        | _ => panic!("Expected markup content"),
    }
}
