use crate::model::{BlockType, DocumentBlock, DocumentModel};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OutlineEntry {
    pub block_id: String,
    pub level: u8,
    pub title: String,
    pub depth: usize,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VisibilitySnapshot {
    pub visible_block_ids: Vec<String>,
    pub outline: Vec<OutlineEntry>,
}

impl VisibilitySnapshot {
    pub fn derive(document: &DocumentModel) -> Self {
        let mut hidden_ancestor_ids: Vec<String> = Vec::new();
        let mut visible_block_ids = Vec::new();
        let mut outline = Vec::new();

        for block in document.blocks() {
            hidden_ancestor_ids.retain(|ancestor_id| is_ancestor_of(document, ancestor_id, block));
            let visible = hidden_ancestor_ids.is_empty();
            if visible {
                visible_block_ids.push(block.id.clone());
            }

            if matches!(block.block_type, BlockType::Heading) {
                let level = block.heading_level.unwrap_or(1);
                if visible {
                    outline.push(OutlineEntry {
                        block_id: block.id.clone(),
                        level,
                        title: block.content.text.clone(),
                        depth: block.indent as usize,
                    });
                }
                if block.collapsed {
                    hidden_ancestor_ids.push(block.id.clone());
                }
            }
        }

        Self {
            visible_block_ids,
            outline,
        }
    }
}

fn is_ancestor_of(document: &DocumentModel, ancestor_id: &str, block: &DocumentBlock) -> bool {
    document.is_descendant_of(&block.id, ancestor_id)
}
