""" Document structure abstractions for doc_file_processing """

from __future__ import annotations

from abc import ABCMeta, abstractmethod
from dataclasses import dataclass
from datetime import datetime
from functools import cached_property
import re
from typing import Any, Optional, TYPE_CHECKING, Union
if TYPE_CHECKING: from _typeshed import StrPath


__all__ = ['Document', 'Chapter', 'TextBlock', 'Table', 'Figure', 'Content',
           'Reader', 'CAPTION_TEXT_RE']


@dataclass
class Document:
    children: list[Content]

    def __str__(self) -> str:
        return '<Document>'

@dataclass
class Chapter:
    title: str
    level: int
    children: list[Content]
    
    @cached_property
    def tag(self) -> str:
        if self.children and isinstance(self.children[0], TextBlock):
            header = self.children[0].text
            if ' - ' in header:
                return header.split(' - ', 1)[0]
        return ''

    def describe(self) -> str:
        """ Generate a string containing the name of the chapter plus some brief additional information (for error messages). """
        return f"{self.title} [{self.tag or 'no tag'}]"

    def __str__(self) -> str:
        return f'<Chapter "{self.title}">'

@dataclass
class TextBlock:
    text: str

    def __str__(self) -> str:
        return '<Text block>'

@dataclass
class Table:
    index: Optional[int]
    caption: str
    headers: tuple[str, ...]
    data: tuple[tuple[str, ...], ...]

    def __len__(self) -> int:
        return len(self.data)
    
    def __str__(self) -> str:
        return f'<Table "{self.caption}">'

@dataclass
class Figure:
    index: Optional[int]
    caption: str
    key: Any

    def __str__(self) -> str:
        return f'<Figure "{self.caption}">'

Content = Union[Chapter, TextBlock, Figure, Table]


CAPTION_TEXT_RE = re.compile(r'^(Figure|Table) (?P<index>\d+)\. (?P<name>.*)$')


class Reader(metaclass=ABCMeta):
    """ Abstract base class for a document reader """

    @abstractmethod
    def parse(self) -> Document:
        ...
    
    @abstractmethod
    def write_image(self, key: Any, dst: StrPath) -> None:
        ...
        
    @abstractmethod
    def timestamp(self) -> datetime:
        ...

    @abstractmethod
    def is_config(self) -> bool:
        ...