"""
BlockMD Export API - Export blocks to various formats.

This module provides exporters and view formatters for BlockMD blocks:
- TreeView: Display blocks as tree structure
- TableView: Display blocks as table
- ListView: Display blocks as simple list
- BMDExporter: Export blocks back to BlockMD format
"""

from typing import List, Optional
from pathlib import Path


# Import Block from parser module
from .parser import Block


# ============================================================================
# View Formatters
# ============================================================================

class TreeView:
    """Format blocks as tree structure."""
    
    def render(self, blocks: List['Block']) -> str:
        """
        Render blocks as tree.
        
        Args:
            blocks: List of blocks to render
            
        Returns:
            Tree-formatted string
        """
        # Group blocks by root
        roots = [b for b in blocks if b.is_root()]
        if not roots:
            # If no roots, find top-level blocks in the result set
            roots = [b for b in blocks if b.parent not in blocks]
        
        lines = []
        for root in roots:
            self._render_block(root, '', True, lines, blocks)
        
        return '\n'.join(lines)
    
    def _render_block(
        self, 
        block: 'Block', 
        prefix: str, 
        is_last: bool, 
        lines: List[str],
        visible_blocks: List['Block']
    ) -> None:
        """Recursively render block and children."""
        # Determine symbols
        connector = '└── ' if is_last else '├── '
        
        # Format block info
        props = []
        for key, value in block.properties.items():
            props.append(f"{key}={value}")
        prop_str = f" [{', '.join(props)}]" if props else ""
        
        lines.append(f"{prefix}{connector}{block.title}{prop_str}")
        
        # Recurse for children that are in visible set
        visible_children = [c for c in block.children if c in visible_blocks]
        for i, child in enumerate(visible_children):
            is_last_child = (i == len(visible_children) - 1)
            extension = '    ' if is_last else '│   '
            self._render_block(
                child, 
                prefix + extension, 
                is_last_child, 
                lines,
                visible_blocks
            )


class TableView:
    """Format blocks as table."""
    
    def __init__(self, fields: List[str]):
        """
        Initialize table view.
        
        Args:
            fields: List of fields to display as columns
        """
        self.fields = fields
    
    def render(self, blocks: List['Block']) -> str:
        """
        Render blocks as table.
        
        Args:
            blocks: List of blocks to render
            
        Returns:
            Table-formatted string
        """
        if not blocks:
            return "No results"
        
        # Collect data
        rows = []
        for block in blocks:
            row = []
            for field in self.fields:
                if field == 'title':
                    row.append(block.title)
                elif field == 'level':
                    row.append(str(block.level))
                elif field == 'content':
                    content = block.get_content_text()
                    # Truncate long content
                    row.append(content[:50] + '...' if len(content) > 50 else content)
                elif field == 'path':
                    row.append(block.get_path_string())
                elif field == 'depth':
                    row.append(str(block.get_depth()))
                else:
                    # Property
                    row.append(block.get_property(field, ''))
            rows.append(row)
        
        # Calculate column widths
        col_widths = [len(f) for f in self.fields]
        for row in rows:
            for i, cell in enumerate(row):
                col_widths[i] = max(col_widths[i], len(str(cell)))
        
        # Build table
        lines = []
        
        # Header
        header = ' | '.join(
            f.ljust(col_widths[i]) 
            for i, f in enumerate(self.fields)
        )
        lines.append(header)
        
        # Separator
        separator = '-+-'.join('-' * w for w in col_widths)
        lines.append(separator)
        
        # Rows
        for row in rows:
            line = ' | '.join(
                str(cell).ljust(col_widths[i]) 
                for i, cell in enumerate(row)
            )
            lines.append(line)
        
        return '\n'.join(lines)


class ListView:
    """Format blocks as simple list."""
    
    def __init__(self, fields: Optional[List[str]] = None):
        """
        Initialize list view.
        
        Args:
            fields: Optional list of fields to display
        """
        self.fields = fields
    
    def render(self, blocks: List['Block']) -> str:
        """
        Render blocks as list.
        
        Args:
            blocks: List of blocks to render
            
        Returns:
            List-formatted string
        """
        lines = []
        for i, block in enumerate(blocks, 1):
            if self.fields:
                parts = []
                for field in self.fields:
                    if field == 'title':
                        parts.append(block.title)
                    elif field == 'level':
                        parts.append(f"level={block.level}")
                    elif field == 'path':
                        parts.append(block.get_path_string())
                    else:
                        val = block.get_property(field)
                        if val:
                            parts.append(f"{field}={val}")
                lines.append(f"{i}. {' | '.join(parts)}")
            else:
                lines.append(f"{i}. {block.title} (level {block.level})")
        
        return '\n'.join(lines) if lines else "No results"


# ============================================================================
# BMD Exporter
# ============================================================================

class BMDExporter:
    """Export blocks back to BlockMD format."""
    
    def __init__(self, indent_content: bool = True):
        """
        Initialize BMD exporter.
        
        Args:
            indent_content: Whether to indent content under blocks
        """
        self.indent_content = indent_content
    
    def export(self, blocks: List['Block']) -> str:
        """
        Export blocks to BMD format string.
        
        Args:
            blocks: List of blocks to export
            
        Returns:
            BMD-formatted string
        """
        lines = []
        
        # Get root blocks
        roots = [b for b in blocks if b.is_root()]
        if not roots:
            # If no roots, treat all blocks as roots
            roots = blocks
        
        # Collect all blocks including descendants for visibility check
        visible_blocks = []
        for block in blocks:
            self._collect_descendants(block, visible_blocks)
        
        for root in roots:
            self._export_block(root, lines, visible_blocks)
        
        return '\n'.join(lines)
    
    def _collect_descendants(self, block: 'Block', result: list) -> None:
        """Recursively collect block and all descendants."""
        result.append(block)
        for child in block.children:
            self._collect_descendants(child, result)
    
    def export_to_file(self, blocks: List['Block'], path: str) -> None:
        """
        Export blocks to BMD file.
        
        Args:
            blocks: List of blocks to export
            path: Output file path
        """
        content = self.export(blocks)
        Path(path).write_text(content, encoding='utf-8')
    
    def _export_block(
        self, 
        block: 'Block', 
        lines: List[str],
        visible_blocks: List['Block']
    ) -> None:
        """Recursively export block and children."""
        # Build header line
        header = '#' * block.level + ' ' + block.title
        lines.append(header)
        
        # Add properties (each on its own line with backtick format)
        if block.properties:
            for key, value in block.properties.items():
                lines.append(f'`{key}`: {value}')
            # Add blank line after properties
            if block.content or block.children:
                lines.append('')
        
        # Add content
        if block.content:
            content_text = block.get_content_text()
            if content_text:
                lines.extend(content_text.split('\n'))
                
                # Add blank line after content if there are children
                if block.children:
                    lines.append('')
        
        # Export visible children
        visible_children = [c for c in block.children if c in visible_blocks]
        for i, child in enumerate(visible_children):
            self._export_block(child, lines, visible_blocks)
            # Add blank line between blocks (but not after the last one)
            if i < len(visible_children) - 1:
                lines.append('')


# ============================================================================
# Convenience Functions
# ============================================================================

def export_to_bmd(blocks: List['Block'], path: Optional[str] = None) -> str:
    """
    Export blocks to BMD format.
    
    Args:
        blocks: List of blocks to export
        path: Optional file path to write to
        
    Returns:
        BMD-formatted string
        
    Example:
        >>> content = export_to_bmd(blocks)
        >>> export_to_bmd(blocks, 'output.bmd')
    """
    exporter = BMDExporter()
    content = exporter.export(blocks)
    
    if path:
        exporter.export_to_file(blocks, path)
    
    return content


def render_tree(blocks: List['Block']) -> str:
    """
    Render blocks as tree view.
    
    Args:
        blocks: List of blocks to render
        
    Returns:
        Tree-formatted string
    """
    return TreeView().render(blocks)


def render_table(blocks: List['Block'], fields: List[str]) -> str:
    """
    Render blocks as table view.
    
    Args:
        blocks: List of blocks to render
        fields: List of fields to display as columns
        
    Returns:
        Table-formatted string
    """
    return TableView(fields).render(blocks)


def render_list(blocks: List['Block'], fields: Optional[List[str]] = None) -> str:
    """
    Render blocks as list view.
    
    Args:
        blocks: List of blocks to render
        fields: Optional list of fields to display
        
    Returns:
        List-formatted string
    """
    return ListView(fields).render(blocks)
