use tombi_syntax::SyntaxKind::{KEY_VALUE, KEY_VALUE_GROUP};
use tombi_syntax::{SyntaxElement, SyntaxKind, SyntaxNode};

fn children_matching_kind(node: &SyntaxNode, target: SyntaxKind) -> Vec<SyntaxElement> {
    let mut result = Vec::new();
    for entry in node.children_with_tokens() {
        if entry.kind() == target {
            result.push(entry);
        } else if target == KEY_VALUE && entry.kind() == KEY_VALUE_GROUP {
            for kv in entry.as_node().unwrap().children_with_tokens() {
                if kv.kind() == KEY_VALUE {
                    result.push(kv);
                }
            }
        }
    }
    result
}

pub fn iter<F>(node: &SyntaxNode, paths: &[SyntaxKind], handle: &F)
where
    F: Fn(&SyntaxNode),
{
    for entry in children_matching_kind(node, paths[0]) {
        let found = entry.as_node().unwrap();
        if paths.len() == 1 {
            handle(found);
        } else {
            iter(found, &paths[1..], handle);
        }
    }
}

pub fn find_first<F, T>(node: &SyntaxNode, paths: &[SyntaxKind], extract: &F) -> Option<T>
where
    F: Fn(SyntaxElement) -> T,
{
    for entry in children_matching_kind(node, paths[0]) {
        if paths.len() == 1 {
            return Some(extract(entry));
        } else if let Some(result) = find_first(entry.as_node().unwrap(), &paths[1..], extract) {
            return Some(result);
        }
    }
    None
}

pub fn is_group_marker(comment_text: &str) -> bool {
    comment_text
        .trim_start()
        .strip_prefix('#')
        .map(str::trim_start)
        .and_then(|rest| rest.get(..6))
        .is_some_and(|head| head.eq_ignore_ascii_case("group:"))
}

pub fn limit_blank_lines(content: &str, max_blank_lines: usize) -> String {
    let lines: Vec<&str> = content.lines().collect();
    let mut result = Vec::new();
    let mut consecutive_blanks = 0;

    for line in lines {
        let trimmed_line = line.trim_end();
        if trimmed_line.is_empty() {
            consecutive_blanks += 1;
            if consecutive_blanks <= max_blank_lines {
                result.push(trimmed_line);
            }
        } else {
            consecutive_blanks = 0;
            result.push(trimmed_line);
        }
    }

    let output = result.join("\n");
    if content.ends_with('\n') {
        format!("{output}\n")
    } else {
        output
    }
}
