import argparse
import logging
import os
import sys

import pygit2

from gitubuntu.git_repository import GitUbuntuRepository, git_dep14_tag

def parse_args(subparsers=None, base_subparsers=None):
    kwargs = dict(description='Given a %(prog)s import\'d tree, tag a commit respecting DEP14',
                  formatter_class=argparse.RawTextHelpFormatter,
                  epilog='By default, an upload tag is created. Working tree must be clean.'
                 )
    if base_subparsers:
        kwargs['parents'] = base_subparsers
    if subparsers:
        parser = subparsers.add_parser('tag', **kwargs)
        parser.set_defaults(func=cli_main)
    else:
        parser = argparse.ArgumentParser(**kwargs)

    parser.add_argument('commitish',
                        help='Commitish to tag',
                        type=str,
                        default='HEAD',
                        nargs='?'
                       )
    group = parser.add_mutually_exclusive_group()
    group.add_argument('--logical', action='store_true',
                       help='Equivalent to --format=\'logical/%%(version)s\', with version extracted from the commit tagged as old/ubuntu')
    group.add_argument('--split', action='store_true',
                       help='Equivalent to --format=\'split/%%(version)s\'')
    group.add_argument('--reconstruct', action='store_true',
                       help='Equivalent to --format=\'reconstruct/%%(version)s\'')
    group.add_argument('--upload', action='store_true',
                       help='Equivalent to --format=\'upload/%%(version)s\'')
    group.add_argument('--format', type=str,
                       help='Use FORMAT when tagging commit'
                      )
    parser.add_argument('--bug',
                        help='Launchpad bug for the tags (primarily '
                             'used in the merge workflow)',
                        type=str)
    parser.add_argument('-d', '--directory', type=str,
                        help='Use git repository at specified location.',
                        default=os.path.abspath(os.getcwd())
                       )
    parser.add_argument('-f', '--force',
                        help='Overwrite existing tags and branches, where '
                             'applicable.',
                        action='store_true'
                       )
    parser.add_argument(
        '--print-name-only',
        help="No-op: only print the name of the tag that would be created",
        action='store_true',
    )
    if not subparsers:
        return parser.parse_args()
    return 'tag - %s' % kwargs['description']

def cli_main(args):
    return main(
        args.directory,
        args.commitish,
        args.force,
        args.bug,
        args.logical,
        args.reconstruct,
        args.split,
        args.upload,
        args.format,
        args.print_name_only,
    )

def main(
    directory,
    commitish,
    force,
    bug,
    logical,
    reconstruct,
    split,
    upload,
    _format,
    print_name_only,
):
    # Suppress INFO logging in case --print-name-only has been used
    logging.getLogger().setLevel(logging.WARNING)

    repo = GitUbuntuRepository(directory)

    changelog_commitish = commitish

    msg_format = None
    tag_prefix = ''
    if bug:
        tag_prefix = 'lp%s/' % bug

    if logical:
        fmt = '%slogical/%%(version)s' % tag_prefix
        changelog_commitish = 'old/ubuntu'
        msg_format = 'Logical delta of %(version)s'
    elif reconstruct:
        fmt = '%sreconstruct/%%(version)s' % tag_prefix
        msg_format = 'Reconstruct delta of %(version)s'
    elif split:
        fmt = '%ssplit/%%(version)s' % tag_prefix
        msg_format = 'split delta of %(version)s'
    elif upload:
        fmt = '%supload/%%(version)s' % tag_prefix
        msg_format = 'Upload of %(version)s to %(dist)s'
    elif _format:
        fmt = '%s%s' % (tag_prefix, _format)
    else:
        fmt = '%supload/%%(version)s' % tag_prefix
        msg_format = 'Upload of %(version)s to %(dist)s'

    try:
        repo.get_commitish(commitish)
        repo.get_commitish(changelog_commitish)
    except KeyError:
        logging.error(
            "%s is not a defined object in this git repository.",
            commitish
        )
        return 1

    work_tree_is_clean = all(
        s == pygit2.GIT_STATUS_IGNORED
        for s in repo.raw_repo.status().values()
    )
    if not work_tree_is_clean:
        logging.error('Working tree must be clean to continue.')
        return 1

    version, _ = repo.get_changelog_versions_from_treeish(changelog_commitish)
    dist = repo.get_changelog_distribution_from_treeish(changelog_commitish)
    tag = fmt % {'version': git_dep14_tag(version)}
    msg = None
    if msg_format:
        msg = msg_format % {'version': version, 'dist': dist}

    if print_name_only:
        print(tag)
    else:
        try:
            repo.annotated_tag(
                tag,
                commitish,
                force,
                msg,
            )
        except:
            return 1

    return 0
