#!/usr/bin/python3

import time
import os
import sys
import gitlab

CERBERO_PROJECT = 'gstreamer/cerbero'


class Status:
    FAILED = 'failed'
    MANUAL = 'manual'
    CANCELED = 'canceled'
    SUCCESS = 'success'
    SKIPPED = 'skipped'
    CREATED = 'created'

    @classmethod
    def is_finished(cls, state):
        return state in [
            cls.FAILED,
            cls.MANUAL,
            cls.CANCELED,
            cls.SUCCESS,
            cls.SKIPPED,
        ]


def fprint(msg):
    print(msg, end="")
    sys.stdout.flush()


if __name__ == "__main__":
    server = os.environ['CI_SERVER_URL']
    gl = gitlab.Gitlab(server,
                       private_token=os.environ.get('GITLAB_API_TOKEN'),
                       job_token=os.environ.get('CI_JOB_TOKEN'))

    def get_matching_user_project(project, branch):
        cerbero = gl.projects.get(project)
        # Search for matching branches, return only if the branch name matches
        # exactly
        for b in cerbero.branches.list(search=cerbero_branch, iterator=True):
            if branch == b.name:
                return cerbero
        return None

    cerbero = None
    # Only look for user namespace cerbero branch when running in a merge request
    if "CI_MERGE_REQUEST_SOURCE_BRANCH_NAME" in os.environ:
        print("GStreamer monorepo merge request")
        cerbero_branch = os.environ["CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"]
        user_project_path = os.environ["CI_MERGE_REQUEST_SOURCE_PROJECT_PATH"]
        user_ns = os.path.dirname(user_project_path)
        cerbero_name = f'{user_ns}/cerbero'
        # We do not want to run on (often out of date) user upstream branch
        if os.environ["CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"] != os.environ["GST_UPSTREAM_BRANCH"]:
            try:
                cerbero = get_matching_user_project(cerbero_name, cerbero_branch)
            except gitlab.exceptions.GitlabGetError as e:
                print("No matching user project found: " + str(e))
                pass

    if cerbero is None:
        print("Using gstreamer org namespace")
        cerbero_name = CERBERO_PROJECT
        cerbero_branch = os.environ["GST_UPSTREAM_BRANCH"]
        cerbero = gl.projects.get(cerbero_name)

    fprint(f"-> Triggering on branch {cerbero_branch} in {cerbero_name}\n")

    # CI_PROJECT_URL is not necessarily the project where the branch we need to
    # build resides, for instance merge request pipelines can be run on
    # 'gstreamer' namespace. Fetch the branch name in the same way, just in
    # case it breaks in the future.
    if 'CI_MERGE_REQUEST_SOURCE_PROJECT_URL' in os.environ:
        project_path = os.environ['CI_MERGE_REQUEST_SOURCE_PROJECT_PATH']
        project_branch = os.environ['CI_MERGE_REQUEST_SOURCE_BRANCH_NAME']
    else:
        project_path = os.environ['CI_PROJECT_PATH']
        project_branch = os.environ['CI_COMMIT_REF_NAME']

    variables = {
        "CI_GSTREAMER_PATH": project_path,
        "CI_GSTREAMER_REF_NAME": project_branch,
        # This tells cerbero CI that this is a pipeline started via the
        # trigger API, which means it can use a deps cache instead of
        # building from scratch.
        "CI_GSTREAMER_TRIGGERED": "true",
    }

    meson_commit = os.environ.get('MESON_COMMIT')
    if meson_commit:
        # Propagate the Meson commit to cerbero pipeline and make sure it's not
        # using deps cache.
        variables['MESON_COMMIT'] = meson_commit
        del variables['CI_GSTREAMER_TRIGGERED']

    try:
        pipe = cerbero.trigger_pipeline(
            token=os.environ['CI_JOB_TOKEN'],
            ref=cerbero_branch,
            variables=variables,
        )
    except gitlab.exceptions.GitlabCreateError as e:
        if e.response_code == 400:
            exit('''

            Could not start cerbero sub-pipeline due to insufficient permissions.

            This is not a problem and is expected if you are not a GStreamer
            developer with merge permission in the cerbero project.

            When your Merge Request is assigned to Marge (our merge bot), it
            will trigger the cerbero sub-pipeline with the correct permissions.
            ''')
        else:
            exit(f'Could not create cerbero sub-pipeline. Error: {e}')

    fprint(f'Cerbero pipeline running at {pipe.web_url} ')
    while True:
        time.sleep(15)
        pipe.refresh()
        if Status.is_finished(pipe.status):
            fprint(f": {pipe.status}\n")
            sys.exit(0 if pipe.status == Status.SUCCESS else 1)
        else:
            fprint(".")