from __future__ import annotations

from typing import Iterator, Optional

class Document:
    def __init__(self, url: str, doc: str): ...
    def select(self, query: str) -> list[ElementRefView]: ...

class ContextExtractor:
    def __init__(
        self,
        ignored_tags: Optional[list[str]] = None,
        discard_tags: Optional[list[str]] = None,
        same_content_level_elements: Optional[list[str]] = None,
        header_elements: Optional[list[str]] = None,
        only_keep_inline_tags: bool = True,
    ): ...

class TableExtractor:
    def __init__(
        self,
        *,
        context_extractor: ContextExtractor,
        ignored_tags: Optional[list[str]] = None,
        discard_tags: Optional[list[str]] = None,
        only_keep_inline_tags: bool = True,
        html_error_forgiveness: bool = True,
    ) -> None: ...
    def extract(
        self,
        url: str,
        doc: str,
        auto_span: bool = True,
        auto_pad: bool = True,
        extract_context: bool = True,
    ) -> list[Table]: ...

class Table:
    id: str
    url: str
    caption: str

    def __init__(
        self,
        id: str,
        url: str,
        caption: str,
        attrs: dict[str, str],
        context: list[ContentHierarchy],
        rows: list[Row],
    ) -> None: ...
    @property
    def attrs(self) -> dict[str, str]: ...
    @property
    def context(self) -> list[ContentHierarchy]: ...
    @property
    def rows(self) -> list[Row]: ...
    def span(self) -> Table: ...
    def pad(self) -> Optional[Table]: ...
    def n_rows(self) -> int: ...
    def shape(self) -> tuple[int, int]: ...
    def get_row(self, ri: int) -> Row: ...
    def get_cell(self, ri: int, ci: int) -> Cell: ...
    def iter_cells(self) -> Iterator[Cell]: ...
    def enumerate_cells(self) -> Iterator[tuple[int, int, Cell]]: ...
    def iter_rows(self) -> Iterator[Row]: ...
    def to_bytes(self) -> bytes: ...
    @staticmethod
    def from_bytes(dat: bytes) -> Table: ...
    def to_json(self) -> str: ...
    @staticmethod
    def from_json(dat: str) -> Table: ...
    def to_base64(self) -> str: ...
    @staticmethod
    def from_base64(dat: str) -> Table: ...
    def to_dict(self) -> dict: ...
    def to_list(self) -> list[list[str]]: ...

class Row:
    def __init__(self, cells: list[Cell], attrs: dict[str, str]) -> None: ...
    @property
    def cells(self) -> list[Cell]: ...
    @property
    def attrs(self) -> dict[str, str]: ...
    def get_cell(self, ci: int) -> Cell: ...
    def iter_cells(self) -> Iterator[Cell]: ...
    def to_dict(self) -> dict: ...
    def to_list(self) -> list[str]: ...

class Cell:
    is_header: bool
    rowspan: int
    colspan: int
    value: RichText

    def __init__(
        self, is_header: bool, rowspan: int, colspan: int, value: RichText
    ) -> None: ...
    @property
    def attrs(self) -> dict[str, str]: ...
    def to_dict(self) -> dict: ...

class ContentHierarchy:
    level: int
    heading: RichText

    @property
    def content_before(self) -> list[RichText]: ...
    @property
    def content_after(self) -> list[RichText]: ...
    def to_dict(self) -> dict: ...
    @staticmethod
    def from_dict(c: dict) -> ContentHierarchy: ...

class ElementRefView:
    def select(self, query: str) -> list[ElementRefView]: ...
    def name(self) -> str: ...
    def id(self) -> str: ...
    def attr(self, name: str) -> str: ...
    def attrs(self) -> Iterator[tuple[str, str]]: ...
    def classes(self) -> list[str]: ...
    def has_class(self, cls: str, case_sensitive: bool = True) -> bool: ...
    def html(self) -> str: ...
    def inner_html(self) -> str: ...
    def get_text(self) -> str: ...
    def get_rich_text(self, cfg: RichTextConfig) -> RichText: ...

class RichTextConfig:
    def __init__(
        self,
        ignored_tags: list[str],
        only_inline_tags: bool,
        discard_tags: list[str],
        keep_tags: list[str],
    ) -> None:
        """
        Arguments:
            ignored_tags: tags to be ignored and not include in the trace (its text is stilled captured but the element containing the text is not stored and thus, cannot be traced back)
            only_inline_tags: whether to only keep inline tags
            discard_tags: tags to be discarded (its text is not captured)
            keep_tags: tags to be kept (its text is captured)
        """
        ...

class RichText:
    @staticmethod
    def from_str(text: str) -> RichText: ...
    @property
    def text(self) -> str: ...
    def len(self) -> int: ...
    def iter_element_id(self) -> Iterator[int]: ...
    def iter_element_id_preorder(self) -> Iterator[int]: ...
    def get_element_tag_by_id(self, id: int) -> str: ...
    def get_element_attr_by_id(self, id: int, attr: str) -> Optional[str]: ...
    def set_element_attr_by_id(self, id: int, attr: str, value: str) -> None: ...
    def get_element_by_id(self, id: int) -> RichTextElement: ...
    def set_element_by_id(self, id: int, RichTextElement) -> None: ...
    def to_dict(self) -> dict: ...
    @staticmethod
    def from_dict(c: dict) -> RichText: ...

class RichTextElement:
    @property
    def tag(self) -> str: ...
    @property
    def start(self) -> int: ...
    @property
    def end(self) -> int: ...
    @property
    def attrs(self) -> dict[str, str]: ...
    def get_attr(self, name: str) -> str: ...
    def has_attr(self, name: str) -> bool: ...
    def to_dict(self) -> dict: ...
    @staticmethod
    def from_dict(c: dict) -> RichTextElement: ...
