from abc import ABC, abstractmethod

from metripy.Application.Config.Config import Config
from metripy.Application.Config.File.PathResolver import PathResolver
from metripy.Application.Config.GitConfig import GitConfig
from metripy.Application.Config.ProjectConfig import ProjectConfig
from metripy.Application.Config.ReportConfig import ReportConfig
from metripy.Application.Config.FailureConfig import FailureConfig


class ConfigFileReaderInterface(ABC):
    def __init__(self, filename: str):
        self.filename = filename

    @abstractmethod
    def read(self, config: Config) -> None:
        pass

    def resolve_path(self, path: str) -> str:
        return PathResolver.resolve(path)

    def parse_data(self, data: dict, config: Config) -> None:
        # configs
        if configs := data.get("configs"):
            for project_name, project_config in configs.items():
                project_config = self.parse_config_json(project_name, project_config)
                config.project_configs.append(project_config)

        # failure
        if failure := data.get("failure"):
            for exit_code, failures in failure.items():
                exit_code = int(exit_code)
                config.failure[exit_code] = []
                for failure in failures:
                    config.failure[exit_code].append(
                        FailureConfig(
                            failure["value"],
                            failure["severity"],
                            failure.get("amount", 1),
                        )
                    )

        # html_index
        if html_index := data.get("html_index"):
            config.html_index = self.resolve_path(html_index)

    def parse_config_json(self, project_name: str, data: dict) -> ProjectConfig:
        project_config = ProjectConfig(project_name)

        # extensions
        if base_path := data.get("base_path"):
            project_config.base_path = base_path

        # includes
        if includes := data.get("includes"):
            files = []
            # with config file, includes are relative to the config file
            for include in includes:
                include = self.resolve_path(include)
                files.append(include)

            project_config.includes = files

        # extensions
        if extensions := data.get("extensions"):
            project_config.extensions = extensions

        # excludes
        if excludes := data.get("excludes"):
            project_config.excludes = excludes

        # reports
        if reports := data.get("reports"):
            for report_type, path in reports.items():
                path = self.resolve_path(path)
                project_config.reports.append(ReportConfig(report_type, path))

        # git
        if git := data.get("git"):
            project_config.git = GitConfig()
            project_config.git.repo = project_config.base_path
            project_config.git.branch = git.get("branch", project_config.git.branch)

        # composer
        if composer := data.get("composer"):
            project_config.composer = composer

        # pip
        if pip := data.get("pip"):
            project_config.pip = pip

        # npm
        if npm := data.get("npm"):
            project_config.npm = npm

        # trends
        if history_path := data.get("trends"):
            project_config.history_path = self.resolve_path(history_path)

        # code smells
        code_smells = data.get("code_smells", True)
        if not isinstance(code_smells, dict):
            if code_smells == False or code_smells is None:
                project_config.code_smells.disable_all()
        else:
            for code_smell, value in code_smells.items():
                project_config.code_smells.set(code_smell, value)

        return project_config
