#!/usr/bin/env python
import argparse
import os
from os.path import expanduser
import configparser
import regex
from PyInquirer import prompt, Validator, ValidationError

from helperlib.bitbucket.bitbucket_api import BitbucketServer, BitbucketCloud
from helperlib.git.git_cli import Git

config_file = os.path.join(expanduser("~"), '.bitbucket-helper.config')


class UrlValidator(Validator):
    def validate(self, document):
        ok = regex.match('^http(s)?://.*', document.text)

        if not ok:
            raise ValidationError(
                message='Please enter a valid url e.g. https://hostname',
                cursor_position=len(document.text))  # Move cursor to end


def config_bitbucket_server():
    questions = [
        {
            'type': 'input',
            'name': 'host',
            'message': 'Bitbucket server url',
            'validate': UrlValidator
        },
        {
            'type': 'input',
            'name': 'username',
            'message': 'Bitbucket server username',
        },
        {
            'type': 'password',
            'name': 'token',
            'message': 'Bitbucket server personal access token',
        },
        {
            'type': 'list',
            'name': 'clone_type',
            'message': 'Git clone using',
            'choices': [
                'http',
                'ssh'
            ]
        },
        {
            'type': 'input',
            'name': 'path',
            'message': 'Working directory',
            'default': os.path.join(expanduser("~"), "bitbucket-server")
        }
    ]

    print("==Bitbucket Server Configuration ==")
    return prompt(questions)


def config_bitbucket_cloud():
    print("==Bitbucket Cloud Configuration ==")
    questions = [
        {
            'type': 'input',
            'name': 'username',
            'message': 'Bitbucket cloud username',
        },
        {
            'type': 'input',
            'name': 'email',
            'message': 'Bitbucket cloud email address',
        },
        {
            'type': 'password',
            'name': 'password',
            'message': 'Bitbucket cloud password',
        },
        {
            'type': 'list',
            'name': 'clone_type',
            'message': 'Git clone using',
            'choices': [
                'https',
                'ssh'
            ]
        },
        {
            'type': 'input',
            'name': 'path',
            'message': 'Working directory',
            'default': os.path.join(expanduser("~"), "bitbucket-cloud")
        }
    ]

    return prompt(questions)


def read_config(force_update=False):
    config = configparser.ConfigParser()

    if not force_update and os.path.isfile(config_file):
        config.read(config_file)
    else:
        server_choice = 'Bitbucket Server'
        cloud_choice = 'Bitbucket Cloud'
        both_choice = 'Both'

        questions = [
            {
                'type': 'list',
                'name': 'config',
                'message': 'Configure ',
                'choices': [
                    server_choice,
                    cloud_choice,
                    both_choice
                ]
            }
        ]

        answers = prompt(questions)

        if answers['config'] in [server_choice, both_choice]:
            config['bitbucket_server'] = config_bitbucket_server()
        if answers['config'] in [cloud_choice, both_choice]:
            config['bitbucket_cloud'] = config_bitbucket_cloud()

        print("Writing config to " + config_file)
        with open(config_file, 'w') as configfile:
            config.write(configfile)

    return config


def get_bitbucket_services(config):
    config = read_config()
    services = []

    for section in config.sections():
        if section == 'bitbucket_server':
            s_config = config[section]
            services.append(BitbucketServer(host=s_config["host"],
                                            user=s_config["username"],
                                            token=s_config["token"],
                                            clone_type=s_config["clone_type"],
                                            working_dir=s_config["path"]))
        if section == 'bitbucket_cloud':
            s_config = config[section]
            services.append(BitbucketCloud(user=s_config["username"],
                                           password=s_config["password"],
                                           email=s_config["email"],
                                           clone_type=s_config["clone_type"],
                                           working_dir=s_config["path"]))

    return services


def get_bitbucket_repos():
    for service in get_bitbucket_services(read_config()):
        git = Git(service.working_dir)

        for repo in service.repos():
            project_key = repo.project['key']
            repo_path = git.local_repo_path(project_key, repo.clone_uri)

            if os.path.exists(repo_path):
                git.pull(repo_path)
                git.prune_local(repo_path)
            else:
                git.clone(project_key, repo.clone_uri)


def list_repos():
    for service in get_bitbucket_services(read_config()):
        for repo in service.repos():
            print("\"{project}\",\"{clone_uri}\"".format(
                project=repo.project['key'], clone_uri=repo.clone_uri))


def list_pull_requests():
    header = "\"project\",\"repo\",\"created\",\"title\",\"state\",\"author\""
    merged_header = "\"project\",\"repo\",\"created\",\"closed\",\"title\",\"state\",\"author\""

    if args.state == 'MERGED':
        print(merged_header)
    else:
        print(header)

    for service in get_bitbucket_services(read_config()):
        for repo in service.repos():
            for pr in service.pull_requests(repo, args.state):
                if pr.state in ('MERGED', 'DECLINED'):
                    print("\"{project}\",\"{repo_name}\",\"{created_date}\",\"{closed_date}\""
                          ",\"{title}\",\"{state}\",\"{author}\"".format(
                              project=pr.repo.project['key'], repo_name=pr.repo.name,
                              created_date=pr.created_date, closed_date=pr.closed_date,
                              title=pr.title, state=pr.state, author=pr.author))
                else:
                    print("\"{project}\",\"{repo_name}\",\"{created_date}\",\"{title}\""
                          ",\"{state}\",\"{author}\"".format(project=pr.repo.project['key'],
                                                             repo_name=pr.repo.name,
                                                             created_date=pr.created_date,
                                                             title=pr.title, state=pr.state,
                                                             author=pr.author))


def gitlog():
    for service in get_bitbucket_services(read_config()):
        git = Git(service.working_dir)
        git.log(args)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(prog='bitbucket-helper')
    sub_parser = parser.add_subparsers(dest='subparser_name')

    parser_clone = sub_parser.add_parser('sync')
    parser_repos = sub_parser.add_parser('repo')

    parser_pr = sub_parser.add_parser('pr')
    parser_pr.add_argument('--state', help='Pull request state ALL, OPEN, MERGED, DECLINED',
                           default='OPEN')

    parser_log = sub_parser.add_parser('log')
    parser_log.add_argument(
        '--after', help='<YYYY-mm-dd> Show commits more recent than a specific date')
    parser_log.add_argument(
        '--from_tag', help='Show commits from this tag')
    parser_log.add_argument(
        '--to_tag', help='Show commit to this tag')

    args = parser.parse_args()
    if args.subparser_name == 'sync':
        get_bitbucket_repos()
    elif args.subparser_name == 'log':
        gitlog()
    elif args.subparser_name == 'repo':
        list_repos()
    elif args.subparser_name == 'pr':
        list_pull_requests()

    else:
        parser.print_help()
