"""Module of Sonar Scanner commands"""

import os
import sys
from enum import Enum

from colorama import Fore
from packaging.version import Version

from common.gitlab_helper import GitlabHelper

sys.path.append("./senior-ci")


from . import (
    ExitCode,
    end_collapsible_section,
    exec_command,
    exit_message,
    get_env_variable,
    get_env_variable_required,
    get_last_version,
    is_semver,
    print_message,
    start_collapsible_section,
)
from .extensions import Extensions
from .file_helpers import load_sdl_properties
from .graphql_client import GraphqlClient


class SonarScannerType(Enum):
    FLUTTER = "FLUTTER"
    MAVEN = "MAVEN"
    SDL = "SDL"
    GO = "GO"
    DOTNET = "DOTNET"
    DELPHI = "DELPHI"


class SonarHelper(object):
    GO_COVERAGE_OUTPUT_PATH = ".coverage-report.txt"

    def __init__(
        self,
        extensions: Extensions = Extensions(),
        sonar_scanner_type: SonarScannerType = None,
        skip_build=False,
    ) -> None:
        self.extensions = extensions
        self.sonar_scanner_type = sonar_scanner_type
        self.skip_build = skip_build
        self.graphql_client = GraphqlClient()

        self.ci_project_path_slug = get_env_variable_required("CI_PROJECT_PATH_SLUG")
        self.ci_project_name = get_env_variable_required("CI_PROJECT_NAME")
        self.ci_commit_branch = get_env_variable("CI_COMMIT_BRANCH")

        self.sci_debug = get_env_variable("SCI_DEBUG")

        self.sonar_url = get_env_variable_required("SONAR_HOST_URL")

    def scanner_analyze(self):
        self.extensions.before_sonar()

        base_sonar_scanner = self._create_base_sonar_scanner()

        section_id = start_collapsible_section(
            "Iniciando a execução do Sonar", Fore.CYAN
        )

        self._config()

        if self.sonar_scanner_type == SonarScannerType.DOTNET:
            base_sonar_scanner = (
                base_sonar_scanner,
                "dotnet build",
                'dotnet sonarscanner end /d:sonar.token="$SONAR_TOKEN"',
            )
            base_sonar_scanner = " && ".join(base_sonar_scanner)

            command_result_sonar = exec_command(base_sonar_scanner)
        elif self.sonar_scanner_type in [SonarScannerType.MAVEN, SonarScannerType.SDL]:
            java_version_command = exec_command(
                "java -version", print_command=False, print_output=False
            )
            java_version = java_version_command.output.split()[2].replace('"', "")

            if not is_semver(java_version) or Version(java_version).major < 17:
                os.environ["JAVA_HOME"] = "/opt/java/openjdk-17"

            command_result_sonar = exec_command(base_sonar_scanner)
        else:
            command_result_sonar = exec_command(base_sonar_scanner)

        if command_result_sonar.exit_code == ExitCode.ERROR:
            exit_message(
                "Analise do projeto realizado pelo SonarQube não foi finalizada com sucesso, "
                "verifique nos logs acima as possíveis resoluções."
            )

        print(" ")
        print_message(
            "Analise estática feita pelo sonar finalizada com sucesso.",
            Fore.GREEN,
        )
        print(" ")

        end_collapsible_section(section_id)

        self.extensions.after_sonar()

    def _append_sonar_report_paths(self, base_default: str) -> str:
        if self.sonar_scanner_type == SonarScannerType.FLUTTER:
            base_default = (
                f"{base_default} -Dsonar.dart.analyzer.mode=MANUAL "
                "-Dsonar.dart.analyzer.report.path=analyzer-output.txt"
            )
        elif self.sonar_scanner_type == SonarScannerType.GO:
            base_default = f"{base_default} -Dsonar.go.coverage.reportPaths={self.GO_COVERAGE_OUTPUT_PATH}"

        return base_default

    def _create_base_sonar_scanner(self):
        ci_project_url = get_env_variable_required("CI_PROJECT_URL")

        last_version_tag = get_last_version()

        if not last_version_tag:
            last_version_tag = self.ci_commit_branch

        base_default = (
            "-Dsonar.sourceEncoding=UTF-8 "
            "-Dsonar.qualitygate.wait=true "
            "-Dsonar.qualitygate.timeout=1800 "
        )

        if self.skip_build:
            exec_command("cp senior-ci/common/default-files/pom.xml .")
            exec_command("cp senior-ci/common/default-files/dummy.sln .")
            exec_command("cp senior-ci/common/default-files/dummy.csproj .")
            base_default = f"{base_default} -Dsonar.exclusions=*.xml,*.sln,*.csproj"

        if self.ci_commit_branch:
            base_default = f"{base_default} -Dsonar.branch.name={self.ci_commit_branch}"

        base_default = self._append_sonar_report_paths(base_default)

        base_urls = (
            f"-Dsonar.host.url={self.sonar_url} -Dsonar.links.scm={ci_project_url}"
        )
        base_ref = f"-Dsonar.projectKey={self.ci_project_path_slug} -Dsonar.projectName={self.ci_project_name}"
        base_version = f"-Dsonar.projectVersion={last_version_tag}"

        base_initial = "sonar-scanner"

        if self.sonar_scanner_type in [SonarScannerType.MAVEN, SonarScannerType.SDL]:
            maven_args = get_env_variable("MAVEN_ARGS")

            base_initial = (
                f"mvn {maven_args} "
                "org.sonarsource.scanner.maven:sonar-maven-plugin:4.0.0.4121:sonar"
            )

            if self.sonar_scanner_type == SonarScannerType.SDL and not self.skip_build:
                properties = load_sdl_properties()

                if not properties:
                    exit_message(
                        "O projeto está usando o script de SDL porém não possui "
                        "nenhuma propriedade no/não possui o arquivo sdl.properties."
                    )

                try:
                    output = properties["generator.java.output"]
                except KeyError:
                    output = "java"

                base_initial = f"{base_initial} --file {output}"

        elif self.sonar_scanner_type == SonarScannerType.DOTNET:
            base_initial = "dotnet sonarscanner begin"

            base_default = base_default.replace("-Dsonar", "/d:sonar")
            base_default = (
                f'{base_default} /d:sonar.token="$SONAR_TOKEN" '
                "/d:sonar.dotnet.excludeTestProjects=true "
                "/d:sonar.cs.opencover.reportsPaths=results/**/*.xml "
            )

            base_urls = base_urls.replace("-Dsonar", "/d:sonar")
            base_ref = base_ref.replace("-Dsonar.projectKey=", "/k:").replace(
                "-Dsonar.projectName=", "/n:"
            )
            base_version = base_version.replace("-Dsonar.projectVersion=", "/v:")
        elif self.sonar_scanner_type == SonarScannerType.DELPHI:
            base_initial = "sonar-scanner.bat"

            old_prefix = "-Dsonar"
            new_prefix = "-D sonar"

            base_default = base_default.replace(old_prefix, new_prefix)
            base_urls = base_urls.replace(old_prefix, new_prefix)
            base_ref = base_ref.replace(old_prefix, new_prefix)
            base_version = base_version.replace(old_prefix, new_prefix)

        if self.sci_debug:
            base_initial = f"{base_initial} -X"

        base_sonar_scanner = (
            f"{base_initial} {base_default} {base_urls} {base_ref} {base_version}"
        )

        return base_sonar_scanner.rstrip()

    @staticmethod
    def _get_mr_labels():
        project_id = get_env_variable("CI_PROJECT_ID")
        if not project_id:
            return ""

        labels = get_env_variable("CI_MERGE_REQUEST_LABELS")

        if not labels:
            gitlab_helper = GitlabHelper(int(project_id))
            labels = gitlab_helper.get_recent_merged_mr_labels()

        return labels if labels else ""

    def _config(self):
        """Configure merge request decorators on sonar project"""

        mutation = """
            mutation ($gitlabId: Int!, $sonarKey: String!, $mrLabels: String) {
                configSonarProject(gitlabId: $gitlabId, sonarKey: $sonarKey, mrLabels: $mrLabels) {
                    success
                    result
                }
            }
        """

        mr_label = self._get_mr_labels()

        params = {
            "gitlabId": int(get_env_variable_required("CI_PROJECT_ID")),
            "mrLabels": mr_label,
            "sonarKey": self.ci_project_path_slug,
        }

        self.graphql_client.call(mutation, params)
