from pathlib import Path
from typing import List

from colorama import Fore

from common import (
    end_collapsible_section,
    exit_message,
    get_env_variable_required,
    get_last_version,
    print_message,
    print_messages,
    start_collapsible_section,
)


class ValidateChangelog(object):
    def __init__(self) -> None:
        self.ci_commit_ref_name = get_env_variable_required("CI_COMMIT_REF_NAME")
        self.ci_project_dir = get_env_variable_required("CI_PROJECT_DIR")

        self.changelog = None

    def validate(self):
        section_id = start_collapsible_section(
            "Validando padrões de branch e changelog", Fore.CYAN
        )

        skip_message = None

        if (
            self.ci_commit_ref_name not in ["develop", "master"]
            and "revert-" not in self.ci_commit_ref_name
        ):
            try:
                branch_type, issue_link = self.ci_commit_ref_name.split("/")
            except ValueError:
                exit_message(
                    "Nome de branch inválida. "
                    "O padrão de desenvolvimento é issue_type/issue_key. "
                    "Por exemplo: feature/devops-19872 ou bugfix/devops-19872."
                )

            self.changelog = self._get_last_changelog_block()

            if self.changelog:
                issue_link = issue_link.upper()

                self._is_in_pattern(issue_link)

                if branch_type in ["feature", "bugfix"]:
                    self._jira_issue_is_in_changelog(issue_link)

                    print_message(
                        "Tudo certinho com o Changelog, bom trabalho <3", Fore.GREEN
                    )
                else:
                    skip_message = "A validação de issue no changelog é feita apenas em branches de feature e bugfix."
            else:
                skip_message = "Projeto não possui changelog."
        else:
            skip_message = "A validação de branch não é feita na develop ou master."

        if skip_message:
            print_messages(
                [
                    skip_message,
                    "Pulando rotina de padrões de branch e verificação de issue no changelog.",
                ],
                Fore.YELLOW,
            )

        end_collapsible_section(section_id)

    def _jira_issue_is_in_changelog(self, issue_link):
        is_in = False

        for line in self.changelog:
            if line and issue_link in line:
                is_in = True

        if not is_in:
            exit_message(
                f"A tarefa informada no branch ({issue_link}) não consta no changelog para a próxima versão, "
                "por favor insira ela para continuar."
            )

    def _is_in_pattern(self, issue_link):
        is_in = False

        for line in self.changelog:
            if line and not line.startswith("#") and not line.startswith("["):
                description = line.replace("* ", "", 1)

                if (
                    description == "N/A."
                    or description.startswith(f"[#{issue_link}]")
                    or description.startswith(
                        f"[{issue_link}](https://jira.senior.com.br/browse/{issue_link})"
                    )
                    or description.startswith(
                        f"[{issue_link}](https://megasistemas.atlassian.net/browse/{issue_link})"
                    )
                    or issue_link not in description
                ):
                    is_in = True
                else:
                    print_message("Linha que apresenta divergência:", Fore.YELLOW)
                    print_message(line, Fore.YELLOW)
                    is_in = False
                    break

        if not is_in:
            print_message(
                "Changelog está em desacordo com os padrões definidos pela arquitetura: "
                "https://wiki.senior.com.br/pt-br/Plataforma/Plataforma/Versionamento#changelog",
                Fore.RED,
            )
            exit_message("Por favor revise a linha acima.")

    def _get_last_changelog_block(self) -> List[str]:
        last_changelog_block = []

        path = Path(f"{self.ci_project_dir}/CHANGELOG.md")
        if path.is_file():
            should_collect_line = False

            latest_tag = get_last_version()

            with open(path, "r", encoding="utf-8") as changelog_file:
                for line in changelog_file:
                    line_striped = line.strip()

                    if line_striped and line_striped.startswith("[{date"):
                        should_collect_line = True
                    elif f"# {latest_tag}" in line_striped:
                        break

                    if should_collect_line:
                        last_changelog_block.append(line_striped)

            if not last_changelog_block:
                exit_message(
                    'Não foi possível encontrar o último "bloco" do changelog. '
                    "O arquivo deve seguir o padrão de desenvolvimento contendo os placeholders iniciais. "
                    "https://wiki.senior.com.br/pt-br/Plataforma/Plataforma/Versionamento#changelog"
                )
        else:
            print_message(f"Changelog não encontrado no path: {path}.", Fore.YELLOW)

        return last_changelog_block
