# SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
# SPDX-License-Identifier: GPL-3.0-or-later

import json
import sys
import os
from argparse import ArgumentParser

try:
    path = os.path.split(os.path.abspath(__file__))[0]
    sys.path.append(os.path.join(path, '../bin/util'))
    from common import runCommand
except Exception:
    sys.exit('Could not import common module')


class APIRequester:
    def __init__(self, projectURL, token):
        self.projectURL = projectURL.rstrip('/')
        self.token = token

    def __call__(self, urlSuffix, msg='API request failed'):
        reqURL = self.projectURL + '/' + urlSuffix.lstrip('/')
        reqCmd = 'curl --header "token={}" "{}"'.format(self.token, reqURL)
        data = runCommand(reqCmd, suppressTraceBack=True, errorMessage=msg)
        return json.loads(data)


# if no id is given this returns all pipelines (// is fine)
def pipelineApiSuffix(id=''):
    return 'pipelines/' + str(id) + '/'


# if no commit sha is given this returns all commits (// is fine)
def commitApiSuffix(sha=''):
    return 'repository/commits/' + str(sha) + '/'


parser = ArgumentParser(
    description='Find and print information on a previously run pipeline'
)

parser.add_argument('-p', '--print-format',
                    required=True, choices=['pipeline-id', 'commit-sha'],
                    help='Switch between reporting the pipeline-id/commit-sha')
parser.add_argument('-l', '--look-for',
                    required=True, choices=['latest', 'latest-merge', 'HEAD'],
                    help='Define how to search for pipelines')
parser.add_argument('-m', '--max-tree-depth',
                    required=False, type=int, default=50,
                    help='Maximum number of revisions to consider'
                         ' in search for pipeline candidates')
parser.add_argument('-t', '--access-token',
                    required=True,
                    help='The token to post read requests to the GitLab API')
parser.add_argument('-u', '--project-api-url',
                    required=False,
                    default='https://git.iws.uni-stuttgart.de/api/v4/projects/31/',
                    help='The token to post read requests to the GitLab API')
parser.add_argument('-s', '--pipeline-status',
                    required=False, default='success',
                    help='Status of pipeline candidates (default: success')
parser.add_argument('-e', '--exclude-jobs',
                    required=False, nargs='*',
                    default=['check-pipeline-status'],
                    help='Exclude pipelines that contain the given jobs')
args = vars(parser.parse_args())


requester = APIRequester(args['project_api_url'], args['access_token'])


def isMergeCommit(commitSHA):
    commitInfo = runCommand(f'git show --no-patch {commitSHA}').split('\n')
    return commitInfo[1].startswith('Merge:')


def getLastPipeline(commitSHA):
    return requester(commitApiSuffix(commitSHA))['last_pipeline']


def hasMatchingStatus(pipeline):
    return pipeline['status'] == args['pipeline_status']


def hasExcludeJob(pipeLine):
    suffix = pipelineApiSuffix(pipeLine['id'])
    jobs = requester(suffix.rstrip('/') + '/jobs/')
    return any(j in jobs for j in args['exclude_jobs'])


def findPipeline(commits):
    for commit in commits:
        pipeLine = getLastPipeline(commit)
        if pipeLine is not None:
            if hasMatchingStatus(pipeLine) and not hasExcludeJob(pipeLine):
                return pipeLine
    return None


if args['look_for'] == 'HEAD':
    commits = [runCommand('git rev-list HEAD --max-count=1').strip('\n')]
    if isMergeCommit(commits[0]):
        preSHA = runCommand('git rev-list HEAD --max-count=2').split('\n')[1]
        commits.append(preSHA)
    pipeLine = findPipeline(commits)

elif args['look_for'] == 'latest':
    count = args['max_tree_depth']
    commits = filter(None, runCommand(f'git rev-list HEAD --max-count={count}').split('\n'))
    pipeLine = findPipeline(commits)

elif args['look_for'] == 'latest-merge':
    count = args['max_tree_depth']
    commits = filter(None, runCommand(f'git rev-list HEAD --merges --max-count={count}').split('\n'))
    pipeLine = findPipeline(commits)

if pipeLine is not None:
    if args['print_format'] == 'pipeline-id':
        print(pipeLine['id'])
    elif args['print_format'] == 'commit-sha':
        print(pipeLine['sha'])
else:
    sys.exit('Could not find a successful pipeline')