# NOTE: COPIED FROM https://github.com/dbt-labs/dbt-core/blob/89907f09c8a94d95d2882f909f05143e098746a0/core/dbt/parser/sql.py
import os
from dataclasses import dataclass
from typing import Iterable

from dbt.contracts.graph.manifest import SourceFile
from dbt.contracts.graph.unparsed import UnparsedMacro
from dbt.exceptions import InternalException
from dbt.parser.base import SimpleSQLParser
from dbt.parser.macros import MacroParser
from dbt.parser.search import FileBlock

from faldbt.cp.contracts.graph.parsed import ParsedSqlNode, ParsedMacro
from faldbt.cp.node_types import NodeType


@dataclass
class SqlBlock(FileBlock):
    block_name: str

    @property
    def name(self):
        return self.block_name


class SqlBlockParser(SimpleSQLParser[ParsedSqlNode]):
    def parse_from_dict(self, dct, validate=True) -> ParsedSqlNode:
        if validate:
            ParsedSqlNode.validate(dct)
        return ParsedSqlNode.from_dict(dct)

    @property
    def resource_type(self) -> NodeType:
        return NodeType.SqlOperation

    @staticmethod
    def get_compiled_path(block: FileBlock):
        # we do it this way to make mypy happy
        if not isinstance(block, SqlBlock):
            raise InternalException(
                'While parsing SQL operation, got an actual file block instead of '
                'an SQL block: {}'.format(block)
            )

        return os.path.join('sql', block.name)

    def parse_remote(self, sql: str, name: str) -> ParsedSqlNode:
        source_file = SourceFile.remote(sql, self.project.project_name)
        contents = SqlBlock(block_name=name, file=source_file)
        return self.parse_node(contents)


class SqlMacroParser(MacroParser):
    def parse_remote(self, contents) -> Iterable[ParsedMacro]:
        base = UnparsedMacro(
            path='from remote system',
            original_file_path='from remote system',
            package_name=self.project.project_name,
            raw_sql=contents,
            root_path=self.project.project_root,
            resource_type=NodeType.Macro,
        )
        for node in self.parse_unparsed_macros(base):
            yield node
