# -*- coding: utf-8 -*-
import sys
import re
import semver

from halo import Halo

from suite_py.lib.handler.youtrack_handler import YoutrackHandler
from suite_py.lib.handler.github_handler import GithubHandler
from suite_py.lib.handler.captainhook_handler import CaptainHook
from suite_py.lib.handler import prompt_utils
from suite_py.lib.handler import git_handler as git
from suite_py.lib.handler import drone_handler as drone
from suite_py.lib.logger import Logger
from suite_py.lib.config import Config


youtrack = YoutrackHandler()
github = GithubHandler()
config = Config()
logger = Logger()


def entrypoint(project, timeout):

    commits = []
    lock = CaptainHook()
    if timeout:
        lock.set_timeout(timeout)
    stop_if_prod_locked(project, lock)

    git.fetch(project)
    repo = github.get_repo(project)

    tags = repo.get_tags()
    tag = git.get_last_tag_number(tags)
    latest_release = get_release(repo, tag)

    current_version = latest_release.tag_name if latest_release else tag

    if current_version:
        logger.info(f"La release attuale è {current_version}")
        versions = bump_versions(current_version)
        commits = github.get_commits_since_release(repo, current_version)

        check_migrations_deploy(commits)

        message = "\n".join(["* " + c.commit.message.splitlines()[0] for c in commits])

        logger.info(f"\nLista dei commit:\n{message}\n")

        if not prompt_utils.ask_confirm("Vuoi continuare?"):
            sys.exit()

        new_version = prompt_utils.ask_choices(
            "Seleziona versione:",
            [
                {"name": f"Patch {versions['patch']}", "value": versions["patch"]},
                {"name": f"Minor {versions['minor']}", "value": versions["minor"]},
                {"name": f"Major {versions['major']}", "value": versions["major"]},
            ],
        )

    else:
        # Se non viene trovata la release e non ci sono tag, viene saltato il check delle migrations e l'update delle card su youtrack
        logger.warning("Nessun tag trovato, sto per pubblicare il tag 0.1.0")
        if not prompt_utils.ask_confirm("Sicuro di voler continuare?", default=False):
            sys.exit()
        new_version = "0.1.0"
        message = f"First release with tag {new_version}"

    create_release(repo, new_version, message, project)
    manage_youtrack_card(project, commits, new_version)


def get_release(repo, tag):
    with Halo(text="Loading...", spinner="dots", color="magenta"):
        latest_release = github.get_latest_release_if_exists(repo)
    if latest_release and latest_release.title == tag:
        return latest_release
    return None


def create_release(repo, new_version, message, project):
    new_release = repo.create_git_release(
        new_version, new_version, youtrack.replace_card_names_with_md_links(message)
    )
    if new_release:
        logger.info(f"La release è stata creata! Link: {new_release.html_url}")

        build_number = drone.get_build_from_tag(project, new_version)
        if build_number:
            drone_url = drone.get_build_url(project, build_number)
            logger.info(f"Puoi seguire il deploy in produzione su {drone_url}")


def bump_versions(current):
    return {
        "patch": semver.bump_patch(current),
        "minor": semver.bump_minor(current),
        "major": semver.bump_major(current),
    }


def deployed_cards_to_string(cards):
    if cards:
        return "\n".join(cards)
    return ""


def check_migrations_deploy(commits):
    if not commits:
        logger.error("ERRORE: nessun commit trovato")
        sys.exit(-1)
    elif len(commits) == 1:
        files_changed = git.files_changed_between_commits("--raw", f"{commits[0].sha}~")
    else:
        files_changed = git.files_changed_between_commits(
            f"{commits[-1].sha}~", commits[0].sha
        )
    if git.migrations_found(files_changed):
        logger.warning("ATTENZIONE: migrations rilevate nel codice")
        if not prompt_utils.ask_confirm("Sicuro di voler continuare?", default=False):
            sys.exit()


def stop_if_prod_locked(project, lock):
    request = lock.status(project, "production")

    if request.status_code != 200:
        logger.error("Impossibile determinare lo stato del lock su master.")
        sys.exit(-1)

    request_object = request.json()
    if request_object["locked"]:
        logger.error(
            f"Il progetto è lockato in produzione da {request_object['by']}. Impossibile continuare."
        )
        sys.exit(-1)


def manage_youtrack_card(project, commits, new_version):
    release_state = config.load()["youtrack"]["release_state"]

    issue_ids = youtrack.get_issue_ids(commits)

    if len(issue_ids) > 0:
        update_youtrack_state = prompt_utils.ask_confirm(
            f"Vuoi spostare le card associate in {release_state}?", default=False
        )

        for issue_id in issue_ids:
            try:
                youtrack.comment(
                    issue_id,
                    f"Deploy in produzione di {project} effettuato con la release {new_version}",
                )
                if update_youtrack_state:
                    youtrack.update_state(issue_id, release_state)
                    logger.info(f"{issue_id} spostata in {release_state}")
            except Exception:
                logger.warning(
                    f"Si è verificato un errore durante lo spostamento della card {issue_id} in {release_state}"
                )
            repos_status = get_repos_status_from_issue(issue_id)
            if all(r["deployed"] for r in repos_status.values()):
                try:
                    youtrack.update_deployed_field(issue_id)
                    logger.info("Custom field Deployed aggiornato su YouTrack")
                except Exception:
                    logger.warning(
                        "Si è verificato un errore durante l'aggiornamento del custom field Deployed"
                    )


def get_repos_status_from_issue(issue_id):
    regex_pr = r"^PR .* -> https:\/\/github\.com\/primait\/(.*)\/pull\/([0-9]*)$"
    regex_deploy = r"^Deploy in produzione di (.*) effettuato con la release"
    comments = youtrack.get_comments(issue_id)
    repos_status = {}

    for c in comments:
        m = re.match(regex_pr, c["text"])
        if m:
            project = m.group(1)
            pr_number = int(m.group(2))
            repos_status[project] = {}
            repos_status[project]["pr"] = pr_number
            repos_status[project]["deployed"] = False
        m = re.match(regex_deploy, c["text"])
        if m:
            project = m.group(1)
            repos_status[project]["deployed"] = True
    return repos_status
