from pathlib import Path
from urllib import parse

from common import (
    ExitCode,
    exec_command,
    exit_message,
    get_env_variable,
    get_env_variable_required,
    is_path_exist,
    print_message,
)
from common.artifactory_helpers import configure_go_repository
from common.sonar_helper import SonarHelper, SonarScannerType
from src.interface.project import ProjectInterface


class GoProjectInterface(ProjectInterface):
    def __init__(self):
        super().__init__()
        self.maven_username = get_env_variable_required("MAVEN_USERNAME")
        self.maven_password = get_env_variable_required("MAVEN_PASSWORD")
        self.sci_go_test_tags = get_env_variable("SCI_GO_TEST_TAGS")

    def validate(self):
        super().validate()
        if not self._go_buildable():
            return
        # self._lint()

    def compile(self):
        if not self._go_buildable():
            return

        self._build_go()
        self._build_go(arch="arm64")

    def _build_go(self, arch=None):

        if arch:
            self._exec_go_command(f"env -w GOARCH={arch}")

        self._exec_go_command(
            "build -o output/$CI_PROJECT_NAME-$(go env GOARCH)",
        )

    def unit_test(self):
        if not self._go_buildable():
            return

        args = ""
        if self.sci_go_test_tags:
            args = f" -tags {self.sci_go_test_tags}"
        self._exec_go_command(
            f"test {args} -v -coverpkg=./... -coverprofile={SonarHelper.GO_COVERAGE_OUTPUT_PATH} ./..."
        )

    def sonar_scanner(self):
        sonar_helper = SonarHelper(sonar_scanner_type=SonarScannerType.GO)
        sonar_helper.scanner_analyze()

    @staticmethod
    def _exec_go_command(command, build_variables=""):
        command_result_go = exec_command(f"{build_variables} go {command}")

        if command_result_go.exit_code == ExitCode.ERROR:
            exit_message("GO command failed. Exiting...")

    def _lint(self):
        print_message("Executando lint")

        if is_path_exist(".lint"):
            exit_message("The folder '.lint' cannot exists in project")

        Path(".lint").mkdir(parents=True)

        lint_command = "golangci-lint run --out-format colored-line-number:stdout,checkstyle:.lint/lint.xml"

        if self.sci_go_test_tags:
            lint_command = f"{lint_command} --build-tags {self.sci_go_test_tags}"

        exec_command(
            lint_command, error_message="Análise estática finalizada com erro."
        )

    def _switch_go_version(self):
        version = self._determine_go_version()

        if version:
            exec_command(
                f"bash switch-go {version}",
                error_message=f"Ocorreu um erro ao tentar trocar a versão do Go para {version}",
            )
        else:
            go_version = get_env_variable("GO_VERSION")

            print_message(
                f"Não foi possível determinar a versão do Go no projeto, usando versão padrão da imagem: {go_version}"
            )

    @staticmethod
    def _determine_go_version():
        """Determines golang version based on go.mod"""

        if is_path_exist("go.mod"):
            with open("go.mod", encoding="utf8") as go_mod:
                lines = go_mod.readlines()
                for line in lines:
                    if line.startswith("go "):
                        return line[3:].strip()

        return None

    def _prepare(self):
        """Prepares the environment to execute golang pipelines"""
        self._switch_go_version()

        configure_go_repository()

        usr = parse.quote(self.maven_username)
        pwd = parse.quote(self.maven_password.replace("\\", ""))

        self._exec_go_command(
            'env -w GOPROXY="https://proxy.golang.org,'
            f"https://{usr}:{pwd}@maven.proxy.senior.com.br/artifactory/go,"
            'direct"'
        )

        self._exec_go_command("env -w GONOSUMDB=git.senior.com.br")
        self._exec_go_command("env -w GOOS=linux")
        self._exec_go_command("env -w GOARCH=amd64")
        self._exec_go_command("env -w CGO_ENABLED=0")
        self._exec_go_command("env -w GOMODCACHE=$CI_PROJECT_DIR/.cache/go-mod")
        self._exec_go_command("env -w GOCACHE=$CI_PROJECT_DIR/.cache/go-build")

    def _go_buildable(self):
        if self.buildable_project.skip_build():
            return False
        self._prepare()
        self._exec_go_command("mod tidy")
        return True
