import gitlab
from gitlab.v4.objects.pipelines import ProjectPipeline
from gitlab.v4.objects.projects import Project
from omnibenchmark.management.data_commands import get_project_info_from_url
from typing import List, Optional
import base64
import yaml


def get_orchestrator_projects_from_cicd_yaml(
    o_url: str,
    gitlab_url: str = "https://renkulab.io/gitlab",
    target_branches: List[str] = ["master", "main"],
    exclude_stages: List[str] = ["build"],
) -> List[str]:
    """Get all projects associated to an orchestrator from the orchestrators gitlab cicd yaml file

    Args:
        o_url (str): Orchestrator url
        gitlab_url (_type_, optional): Gitlab url. Defaults to "https://renkulab.io/gitlab".
        target_branches (List[str], optional): branch(es) to use. Defaults to ["master", "main"].
        exclude_stages (List[str], optional): Stages to ignore. Defaults to ["build"].

    Returns:
        List[str]: Project urls associated to the
    """
    o_info = get_project_info_from_url(o_url)
    renku_git = gitlab.Gitlab(gitlab_url)
    o_git = renku_git.projects.get(o_info["identifier"])
    bs = o_git.branches.list()
    br = [b.name for b in bs if b.name in target_branches][0]
    ci_yml = o_git.files.get(file_path=".gitlab-ci.yml", ref=br)
    fc = base64.b64decode(ci_yml.content).decode("utf-8")
    fc = fc.replace("\\n", "\n")
    dct = yaml.safe_load(fc)
    stages = [stg for stg in dct["stages"] if stg not in exclude_stages]
    trigger_keys = ["stage", "trigger"]
    process = {
        run_nam: run_val
        for run_nam, run_val in dct.items()
        if isinstance(run_val, dict)
        and all(trigger_k in run_val.keys() for trigger_k in trigger_keys)
        and run_val["stage"] in stages
    }
    return [proc["trigger"]["project"] for proc in process.values()]


def get_project_infos(
    p_url: str, gitlab_url: str = "https://renkulab.io/gitlab"
) -> Optional[Project]:
    """Get project info from url

    Args:
        p_url (str): project url
        gitlab_url (_type_, optional): gitlab url. Defaults to "https://renkulab.io/gitlab".

    Returns:
        Project: An instance of gitlab API project class
    """
    p_info = get_project_info_from_url(p_url)
    if "message" in p_info.keys():
        print(f"Warning: Could not find project {p_url}")
        return None
    renku_git = gitlab.Gitlab(gitlab_url)
    return renku_git.projects.get(p_info["identifier"])


def get_last_pipe(
    project: Project, exclude_push: bool = True
) -> Optional[ProjectPipeline]:
    """Get the last pipeline from an project instance

    Args:
        project (Project): An instance of the gitlab api Project class
        exclude_push (bool, optional): if pipelines generated by push shall be excluded. Defaults to True.

    Returns:
        Optional[ProjectPipeline]: AN instance of the gitlab api projectpipeline class
    """
    pipes = project.pipelines.list(order_by="updated_at", get_all=True)
    if exclude_push:
        pipes = [p for p in pipes if p.source != "push"]
    if len(pipes) > 0:
        return pipes[0]  # type:ignore
    else:
        print(f"Warning: Did not find any valid pipeline for project {project.web_url}")
        return None
