//! Position helpers for DEP-3 header regions.

use tower_lsp_server::ls_types::Position;

use crate::position::Source;

/// Return true if `position` falls inside the DEP-3 header portion of
/// the buffer — i.e. before the first `---` / `diff ` / `Index:` line.
/// Positions on or after the diff body return `false` so LSP features
/// don't reach into the unified-diff territory that diff-lsp owns.
///
/// `header_end` is the byte offset where the diff body starts; supply
/// the salsa-cached value (from `Workspace::get_parsed_dep3_header`)
/// when the file is open so we don't recompute it on every call.
pub fn is_in_dep3_header(src: Source<'_>, header_end: usize, position: Position) -> bool {
    let Some(offset) = src.try_position_to_offset(position) else {
        return false;
    };
    let offset: usize = offset.into();
    offset < header_end
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::position::LineIndex;

    fn check(text: &str, position: Position) -> bool {
        let header_end = dep3::lossless::header_end(text);
        let idx = LineIndex::new(text);
        is_in_dep3_header(Source::new(text, &idx), header_end, position)
    }

    #[test]
    fn cursor_in_header_returns_true() {
        let text = "Author: alice\nDescription: bla\n---\n@@ -1 +1 @@\n";
        assert!(check(text, Position::new(0, 0)));
        assert!(check(text, Position::new(1, 5)));
    }

    #[test]
    fn cursor_in_diff_body_returns_false() {
        let text = "Author: alice\n---\n@@ -1 +1 @@\n-x\n+y\n";
        // Line 2 is `---`, line 3 is the hunk header.
        assert!(!check(text, Position::new(2, 0)));
        assert!(!check(text, Position::new(3, 1)));
    }

    #[test]
    fn cursor_at_diff_marker_line_returns_false() {
        let text = "Author: alice\n---\n";
        // Line 1 is `---` (the boundary); positions on it are body.
        assert!(!check(text, Position::new(1, 0)));
    }

    #[test]
    fn header_only_file_is_all_header() {
        let text = "Author: alice\nDescription: bla\n";
        assert!(check(text, Position::new(0, 0)));
        assert!(check(text, Position::new(1, 5)));
    }
}
