from typing import Iterable, Optional

import re

from dbt.clients.jinja import get_rendered
from dbt.contracts.files import SourceFile
from dbt.contracts.graph.parsed import ParsedDocumentation
from dbt.node_types import NodeType
from dbt.parser.base import Parser
from dbt.parser.search import (
    BlockContents, FileBlock, BlockSearcher
)


SHOULD_PARSE_RE = re.compile(r'{[{%]')


class DocumentationParser(Parser[ParsedDocumentation]):
    @property
    def resource_type(self) -> NodeType:
        return NodeType.Documentation

    @classmethod
    def get_compiled_path(cls, block: FileBlock):
        return block.path.relative_path

    def generate_unique_id(self, resource_name: str, _: Optional[str] = None) -> str:
        # because docs are in their own graph namespace, node type doesn't
        # need to be part of the unique ID.
        return '{}.{}'.format(self.project.project_name, resource_name)

    def parse_block(
        self, block: BlockContents
    ) -> Iterable[ParsedDocumentation]:
        unique_id = self.generate_unique_id(block.name)
        contents = get_rendered(block.contents, {}).strip()

        doc = ParsedDocumentation(
            root_path=self.project.project_root,
            path=block.file.path.relative_path,
            original_file_path=block.path.original_file_path,
            package_name=self.project.project_name,
            unique_id=unique_id,
            name=block.name,
            block_contents=contents,
        )
        return [doc]

    def parse_file(self, file_block: FileBlock):
        assert isinstance(file_block.file, SourceFile)
        searcher: Iterable[BlockContents] = BlockSearcher(
            source=[file_block],
            allowed_blocks={'docs'},
            source_tag_factory=BlockContents,
        )
        for block in searcher:
            for parsed in self.parse_block(block):
                self.manifest.add_doc(file_block.file, parsed)
