#!/usr/bin/python3

import sys

import osc.core

import ReviewBot
from osclib.conf import Config, str2bool
from osclib.core import (repository_path_expand, repository_path_search,
                         target_archs)
from osclib.repochecks import installcheck, mirror


class MaintInstCheck(ReviewBot.ReviewBot):
    def __init__(self, *args, **kwargs):
        ReviewBot.ReviewBot.__init__(self, *args, **kwargs)

        # ReviewBot options.
        self.request_default_return = True

    def repository_check(self, repository_pairs, archs):
        project, repository = repository_pairs[0]
        self.logger.info(f'checking {project}/{repository}')

        if not len(archs):
            self.logger.debug(
                f'{project} has no relevant architectures')
            return

        for arch in archs:
            directories = []
            for pair_project, pair_repository in repository_pairs:
                directories.append(
                    mirror(self.apiurl, pair_project, pair_repository, arch))

            parts = installcheck(directories, arch, [], [])
            if len(parts):
                self.comment.append(
                    f'## {repository_pairs[0][1]}/{arch}\n')
                self.comment.extend(parts)

        return len(self.comment) == 0

    def check_one_request(self, req):
        self.comment = []
        self.checked_targets = set()
        overall = super(MaintInstCheck, self).check_one_request(req)
        if len(self.comment):
            msg = '\n'.join(self.comment)
            self.logger.debug(msg)
            if not self.dryrun:
                osc.core.change_review_state(apiurl=self.apiurl,
                                             reqid=req.reqid, newstate='declined',
                                             by_group=self.review_group,
                                             by_user=self.review_user, message=msg)
            # lie to the super class - decline only once
            return None

        return overall

    def check_action_maintenance_release(self, request, action):
        # No reason to special case patchinfo since same source and target
        # projects which is all that repo_checker cares about.

        if action.tgt_project in self.checked_targets:
            return True

        target_config = Config.get(self.apiurl, action.tgt_project)
        if str2bool(target_config.get('repo_checker-project-skip', 'False')):
            # Do not change message as this should only occur in requests
            # targeting multiple projects such as in maintenance workflow in
            # which the message should be set by other actions.
            self.logger.debug(
                f'skipping review of action targeting {action.tgt_project}')
            return True

        repository = target_config.get('main-repo')
        if not repository:
            raise Exception('Missing main-repo in OSRT:Config')

        # Find a repository which links to target project "main" repository.
        repository = repository_path_search(
            self.apiurl, action.src_project, action.tgt_project, repository)
        if not repository:
            raise Exception('Missing repositories')

        repository_pairs = repository_path_expand(
            self.apiurl, action.src_project, repository)

        self.checked_targets.add(action.tgt_project)
        archs = set(target_archs(self.apiurl, action.src_project, repository))
        arch_whitelist = target_config.get('repo_checker-arch-whitelist', None)
        if arch_whitelist:
            archs = set(arch_whitelist.split(' ')).intersection(archs)

        if not self.repository_check(repository_pairs, archs):
            return None

        self.review_messages['accepted'] = 'install check passed'
        return True


class CommandLineInterface(ReviewBot.CommandLineInterface):

    def __init__(self, *args, **kwargs):
        ReviewBot.CommandLineInterface.__init__(self, args, kwargs)
        self.clazz = MaintInstCheck


if __name__ == '__main__':
    app = CommandLineInterface()
    sys.exit(app.main())
