# -*- coding: utf-8 -*-
# Gitless - a version control system built on top of Git
# Licensed under MIT

"""gl tag - List, create, edit or delete tags."""


from gitless import core

from . import helpers, pprint


def parser(subparsers, _):
  """Adds the tag parser to the given subparsers object."""
  desc = 'list, create, or delete tags'
  tag_parser = subparsers.add_parser(
      'tag', help=desc, description=desc.capitalize(), aliases=['tg'])

  list_group = tag_parser.add_argument_group('list tags')
  list_group.add_argument(
      '-r', '--remote',
      help='list remote tags in addition to local tags',
      action='store_true')

  create_group = tag_parser.add_argument_group('create tags')
  create_group.add_argument(
      '-c', '--create', nargs='+', help='create tag(s)', dest='create_t',
      metavar='tag')
  create_group.add_argument(
      '-ci', '--commit',
      help='the commit to tag (only relevant if a new '
      'tag is created; defaults to the HEAD commit)', dest='ci')

  delete_group = tag_parser.add_argument_group('delete tags')
  delete_group.add_argument(
      '-d', '--delete', nargs='+', help='delete tag(s)', dest='delete_t',
      metavar='tag')

  tag_parser.set_defaults(func=main)


def main(args, repo):
  is_list = bool(args.remote)
  is_create = bool(args.create_t or args.ci)
  is_delete = bool(args.delete_t)

  if is_list + is_create + is_delete > 1:
    pprint.err('Invalid flag combination')
    pprint.err_exp('Can only do one of list, create, or delete tags at a time')
    return False

  ret = True
  if args.create_t:
    ret = _do_create(args.create_t, args.ci or 'HEAD', repo)
  elif args.delete_t:
    ret = _do_delete(args.delete_t, repo)
  else:
    _do_list(repo, args.remote)

  return ret


def _do_list(repo, list_remote):
  pprint.msg('List of tags:')
  pprint.exp('do gl tag -c t to create tag t')
  pprint.exp('do gl tag -d t to delete tag t')
  pprint.blank()

  no_tags = True
  for t in (repo.lookup_tag(n) for n in sorted(repo.listall_tags())):
    pprint.item('{0} ➜ tags {1}'.format(t, pprint.commit_str(t.commit)))
    no_tags = False

  if list_remote:
    for r in sorted(repo.remotes, key=lambda r: r.name):
      for t in (r.lookup_tag(n) for n in sorted(r.listall_tags())):
        pprint.item('{0} ➜ tags {1}'.format(t, pprint.commit_str(t.commit)))
        no_tags = False

  if no_tags:
    pprint.item('There are no tags to list')


def _do_create(create_t, dp, repo):
  errors_found = False

  try:
    target = repo.revparse_single(dp)
  except KeyError:
    raise ValueError('Invalid commit {0}'.format(dp))

  for t_name in create_t:
    r = repo
    remote_str = ''
    if '/' in t_name:  # might want to create a remote tag
      maybe_remote, maybe_remote_tag = t_name.split('/', 1)
      if maybe_remote in repo.remotes:
        r = repo.remotes[maybe_remote]
        t_name = maybe_remote_tag
        conf_msg = 'Tag {0} will be created in remote repository {1}'.format(
            t_name, maybe_remote)
        if not pprint.conf_dialog(conf_msg):
          pprint.msg(
              'Aborted: creation of tag {0} in remote repository {1}'.format(
                  t_name, maybe_remote))
          continue
        remote_str = ' in remote repository {0}'.format(maybe_remote)
    try:
      r.create_tag(t_name, target)
      pprint.ok('Created new tag {0}{1}'.format(t_name, remote_str))
    except ValueError as e:
      pprint.err(e)
      errors_found = True

  return not errors_found


def _do_delete(delete_t, repo):
  errors_found = False

  for t_name in delete_t:
    try:
      t = helpers.get_tag(t_name, repo)

      tag_str = 'Tag {0} will be removed'.format(t.tag_name)
      remote_str = ''
      if isinstance(t, core.RemoteTag):
        remote_str = 'from remote repository {0}'.format(t.remote_name)
      if not pprint.conf_dialog('{0} {1}'.format(tag_str, remote_str)):
        pprint.msg('Aborted: removal of tag {0}'.format(t))
        continue

      t.delete()
      pprint.ok('Tag {0} removed successfully'.format(t))
    except ValueError as e:
      pprint.err(e)
      errors_found = True

  return not errors_found
