# third party
import os
from typing import List, Optional

from dbt.cli.main import dbtRunner
from dbt.contracts.graph.manifest import Manifest
from dbt.contracts.results import CatalogArtifact
from loguru import logger


class Dbt:
    def __init__(self, manifest: Optional[Manifest] = None):
        self.dbt_runner = dbtRunner(manifest=manifest)  # type: ignore

    def invoke(
        self, directory: Optional[os.PathLike] = None, runner_args: Optional[List[str]] = None
    ):
        starting_directory = os.getcwd()
        if directory:
            os.chdir(directory)
        result = self.dbt_runner.invoke(runner_args if runner_args else [])
        os.chdir(starting_directory)

        if not result.success and result.exception:
            raise result.exception
        return result.result

    def parse(self, directory: os.PathLike):
        logger.info("Executing dbt parse...")
        return self.invoke(directory, ["--quiet", "parse"])

    def ls(
        self,
        directory: os.PathLike,
        arguments: Optional[List[str]] = None,
        output_key: Optional[str] = None,
    ) -> List[str]:
        """
        Execute dbt ls with the given arguments and return the result as a list of strings.
        Log level is set to none to prevent dbt from printing to stdout.
        """
        args = ["--log-format", "json", "--log-level", "none", "ls"]

        if arguments:
            args.extend(arguments)
        if output_key:
            args.extend(["--output", "json", "--output-keys", output_key])

        return self.invoke(directory, args)

    def docs_generate(self, directory: os.PathLike) -> CatalogArtifact:
        """
        Execute dbt docs generate with the given arguments
        """
        logger.info("Generating catalog with dbt docs generate...")
        args = ["--quiet", "docs", "generate"]
        return self.invoke(directory, args)
