"""Data models for Nhandu documents."""

from __future__ import annotations

import dataclasses
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any

# Type alias for blocks in a document
Block = "MarkdownBlock | CodeBlock"


@dataclass
class MarkdownBlock:
    """A markdown text block."""

    content: str
    line_number: int = 0


@dataclass
class CodeBlock:
    """A code block to be executed."""

    content: str
    hidden: bool = False
    line_number: int = 0
    output: str | None = None
    error: str | None = None
    figures: list[Path] = field(default_factory=list)

    @property
    def has_output(self) -> bool:
        """Whether this block has any renderable output (content, error, or figures)."""
        return bool(self.content.strip() or self.output or self.error or self.figures)


@dataclass
class InlineCode:
    """Inline code within markdown text."""

    expression: str
    is_statement: bool  # True for <% %>, False for <%= %>


@dataclass
class DocumentMetadata:
    """Document metadata from YAML frontmatter."""

    title: str | None = None
    output: str = "markdown"
    plot_dpi: int = 100
    number_format: str = ".4f"
    working_dir: str | None = None
    code_theme: str | None = None
    template: str | None = None
    template_css: str | None = None
    show_footer: bool = True
    raw: dict[str, Any] = field(default_factory=dict)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> DocumentMetadata:
        """Create metadata from a dictionary.

        Builds kwargs from dataclass fields, using each field's default
        so that defaults are never duplicated.
        """
        kwargs: dict[str, Any] = {}
        for f in dataclasses.fields(cls):
            if f.name == "raw":
                continue
            if f.name in data:
                kwargs[f.name] = data[f.name]
        return cls(**kwargs, raw=data)


@dataclass
class Document:
    """A parsed Nhandu document."""

    blocks: list[MarkdownBlock | CodeBlock]
    metadata: DocumentMetadata = field(default_factory=DocumentMetadata)
    source_path: Path | None = None


@dataclass
class ExecutedDocument(Document):
    """A document after code execution."""

    namespace: dict[str, Any] = field(default_factory=dict)
