import argparse
import re
import subprocess
from semver.get_version import get_tag_version

try: 
    from configparser import ConfigParser
except ImportError:
    # Python < 3
    from ConfigParser import ConfigParser

version = '0.0.0'


# Define common exceptions;
NO_MERGE_FOUND = Exception('No merge found')
NOT_MAIN_BRANCH = Exception('Not merging into a main branch')
NO_GIT_FLOW = Exception('No git flow branch found')

class SemVer(object):

    GET_COMMIT_MESSAGE = re.compile(r"Merge (branch|pull request) '?(.+)'? (into|from) ([\w/-]+)")
    # Merge pull request #1 from RightBrain-Networks/feature/PLAT-185-versioning

    def __init__(self,global_user=False):
        self.global_user = '--local' if global_user else '--global'
        self.merged_branch = None
        self.main_branch = None
        self.version_type = None

        self.main_branches = self._setting_to_array('main_branches')
        self.major_branches = self._setting_to_array('major_branches')
        self.minor_branches = self._setting_to_array('minor_branches')
        self.patch_branches = self._setting_to_array('patch_branches')

    def _setting_to_array(self, setting):
        config = ConfigParser()
        config.read('./.bumpversion.cfg')
        value = config.get('semver', setting)
        # filter() removes empty string which is what we get if setting is blank
        return list(filter(bool, [v.strip() for v in value.split(',')]))

    # based on commit message see what branches are involved in the merge
    
    def get_branches(self):
        p = subprocess.Popen(['git', 'log', '-1'], stdout=subprocess.PIPE,
                             cwd='.')
        #check current branch
        b = subprocess.Popen(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], stdout=subprocess.PIPE,
                             cwd='.')
        message = str(p.stdout.read())
        branch = b.stdout.read().decode('utf-8').rstrip()
        print('Main branch is ' + branch)
        matches = self.GET_COMMIT_MESSAGE.search(message)
        if matches:
            if str(matches.group(4)) == branch:
                self.merged_branch = matches.group(2)
            else:
                self.merged_branch = matches.group(4)
            self.main_branch = branch
        return bool(matches)

    # based on branches involved see what type of versioning should be done
    def get_version_type(self):
        print('Merged branch is ' + self.merged_branch)

 
        #Get GitHub repo's owner from url
        repoOwner = None
        remoteUrl = subprocess.Popen(['git', 'config', '--get', 'remote.origin.url'], stdout=subprocess.PIPE).stdout.read().decode('utf-8').rstrip()
        if "github.com" in remoteUrl:
            repoOwner = re.search("(?<=github.com(:|\/))(.*)(?=\/.*.git)", remoteUrl).group(0)

        for prefix in self.major_branches:
            if self.merged_branch.startswith(prefix + '/') or self.merged_branch.startswith(str(repoOwner) + '/' + prefix + '/'):
                self.version_type = 'major'
                return True
        for prefix in self.minor_branches:
            if self.merged_branch.startswith(prefix + '/') or self.merged_branch.startswith(str(repoOwner) + '/' + prefix + '/'):
                self.version_type = 'minor'
                return True
        for prefix in self.patch_branches:
            if self.merged_branch.startswith(prefix + '/') or self.merged_branch.startswith(str(repoOwner) + '/' + prefix + '/'):
                self.version_type = 'patch'
                return True
        return False

    # setup git settings so we can commit and tag
    def setup_git_user(self):
        # setup git user
        p = subprocess.Popen(['git', 'config', self.global_user, 'user.email',
                              '"versioner@semver.com"'],
                             cwd='.')
        p = subprocess.Popen(['git', 'config', self.global_user, 'user.name',
                              '"Semantic Versioner"'],
                             cwd='.')
        p.wait()
        return self

    # use bumpversion to increment the appropriate version type
    def version_repo(self):
        config_file = ""
        with open(".bumpversion.cfg", "r") as file:
            config_file = file.read()
        # Update .bumpconfig
        #pattern = re.compile("current_version = [0-9.]*")
        #current_config = re.search(pattern, config_file)
        #if current_config:
            #config_file.replace(current_config.group(0), "current_version = " + get_tag_version())
        #else:
            #config_file.replace("[bumpversion]","[bumpversion]\ncurrent_version = " + get_tag_version())
        #with open(".bumpversion.cfg", "w") as file:
            #file.write(config_file)

        # version repo
        p = subprocess.Popen(['bumpversion', '--current-version', get_tag_version(), self.version_type],
                             cwd='.')
        p.wait()
        return self

    def commit_and_push(self):
        # push versioning commit
        p = subprocess.Popen(['git', 'push', 'origin', self.main_branch],
                             cwd='.')
        p.wait()

        # push versioning tag
        p = subprocess.Popen(['git', 'push', 'origin', '--tags'],
                             cwd='.')
        p.wait()
        return self

    # 1) get branches from last commit message
    # 2) see if we're merging into a main branch
    # 3) see what type of versioning we should do
    # 4) version the repo
    def run(self,push=True):
        if not self.get_branches():
            raise NO_MERGE_FOUND
        if self.main_branch not in self.main_branches:
            raise NOT_MAIN_BRANCH
        if not self.get_version_type():
            raise NO_GIT_FLOW
        if push:
            self.setup_git_user()
        self.version_repo()
        if push:
            self.commit_and_push()
        return self

def main():
    try:
        parser = argparse.ArgumentParser(description='Bump Semantic Version.')
        parser.add_argument('-n','--no-push', help='Do not try to push', action='store_false', dest='push')
        parser.add_argument('-g','--global-user', help='Set git user at a global level, helps in jenkins', action='store_true', dest='global_user')
        args = parser.parse_args()
        SemVer(global_user=args.global_user).run(push=args.push)
    except Exception as e:
        print(e)
        if e == NO_MERGE_FOUND:
            exit(1)
        elif e == NOT_MAIN_BRANCH:
            exit(2)
        elif e == NO_GIT_FLOW:
            exit(3)
        else:
            exit(128)

if __name__ == '__main__':
    try: main()
    except: raise