const MAX_BODY_SEARCH_SURFACES: usize = 96;
const MAX_BODY_SEARCH_SURFACE_CHARS: usize = 240;

fn scrub_wikilinks(line: &str) -> String {
    let mut out = String::new();
    let mut rest = line;
    while let Some(start) = rest.find("[[") {
        out.push_str(&rest[..start]);
        rest = &rest[start + 2..];
        let Some(end) = rest.find("]]") else {
            out.push_str("[[");
            out.push_str(rest);
            return out;
        };
        let target = &rest[..end];
        if let Some((_, display)) = target.rsplit_once('|') {
            out.push_str(display.trim());
        }
        rest = &rest[end + 2..];
    }
    out.push_str(rest);
    out
}

pub(super) fn body_search_surfaces(body: &str) -> Vec<String> {
    let mut surfaces = Vec::new();
    let mut in_fence = false;
    for raw in body.lines() {
        let line = raw.trim();
        if line.starts_with("```") {
            in_fence = !in_fence;
            continue;
        }
        if in_fence {
            continue;
        }
        let cleaned = line
            .trim_start_matches(['#', '-', '*', '>', '|', ' ', '\t'])
            .trim()
            .trim_end_matches('|')
            .trim();
        let scrubbed = scrub_wikilinks(cleaned);
        let cleaned = scrubbed.trim();
        if cleaned.chars().count() < 3 {
            continue;
        }
        let surface = cleaned
            .chars()
            .take(MAX_BODY_SEARCH_SURFACE_CHARS)
            .collect::<String>();
        if !surfaces.iter().any(|s| s == &surface) {
            surfaces.push(surface);
        }
        if surfaces.len() >= MAX_BODY_SEARCH_SURFACES {
            break;
        }
    }
    surfaces
}

pub(super) fn query_surfaces_from_frontmatter_and_body(
    fm_examples: Vec<String>,
    body: &str,
) -> Vec<String> {
    let mut surfaces = fm_examples;
    for surface in body_search_surfaces(body) {
        if !surfaces.iter().any(|s| s == &surface) {
            surfaces.push(surface);
        }
    }
    surfaces
}

#[cfg(test)]
mod tests {
    use super::body_search_surfaces;

    #[test]
    fn body_surfaces_skip_code_fences_and_scrub_wikilink_targets() {
        let surfaces = body_search_surfaces(
            "## Notes\nVisible fermented barley.\n[[internal-target]]\n[[target|display label]]\n```\nsecret token\n```\n",
        );

        assert!(surfaces.iter().any(|s| s == "Notes"));
        assert!(surfaces.iter().any(|s| s == "Visible fermented barley."));
        assert!(surfaces.iter().any(|s| s == "display label"));
        assert!(!surfaces.iter().any(|s| s.contains("internal-target")));
        assert!(!surfaces.iter().any(|s| s.contains("secret token")));
    }
}
