#!/usr/bin/env python3
from gitz.git import GIT
from gitz.git import functions
from gitz.git import guess_origin
from gitz.git import reference_branch
from gitz.git import root
from gitz.program import ARGS
from gitz.program import ENV
from gitz.program import PROGRAM

SUMMARY = 'Create and push new branches'

HELP = """
Create new branches from the reference branch and push them with
--set-upstream.

``git new`` does the things you really want to safely get new branches
where you can start working and pushing immediately

- Fails leaving the workspace unchanged if there are uncommitted changes

- Fails if any branch already exists locally or remotely, unless -f/--force
  is given.

- Fetches the *reference branch* only - a branch on the upstream or origin repo
  that is the main branch for development - likely upstream/main or origin/main
  or upstream/master or origin/master

- Create new branches locally from that reference branch commit ID

- Pushes them to the remote origin with --set-upstream

gitz can guess what the reference branch and remote origin are, and for
nearly all projects this will be correct, or this can be specified at the
command line, per project, or through environment variables - see ``git gitz``
for more details.
"""

EXAMPLES = """
git new foo
    Create a new branch foo from the reference branch and push to the origin

git new foo --origin=remote_1
git new foo -o remote_1
    Create a new branch foo from the reference branch and push to remote_1

git new one two three --reference-branch=some-remote/main
git new one two three -r some-remote/main
    Create three new branches from the remote branch some-remote/main
"""

_HELP_BRANCHES = 'Names of branches to create'


def git_new():
    if ARGS.use_head:
        root.check_git()
    else:
        root.check_clean_workspace()

    branches = functions.branches()
    remote_branches = functions.remote_branches(False)
    origin = guess_origin.guess_origin(ARGS.origin)

    new_branches = set(ARGS.branches)
    current = functions.branch_name()
    if current in ARGS.branches:
        if ARGS.force or ARGS.protected:
            branches = set(functions.branches()).difference(ARGS.branches)
            if not branches:
                PROGRAM.exit('Cannot overwrite all branches')
            GIT.checkout(min(branches))

    def check(branches, name):
        branches = new_branches.intersection(branches)
        if branches:
            s = 'branch:' if len(branches) == 1 else 'branches:'
            PROGRAM.exit('Cannot overwrite', name, s, *branches)

    if not ARGS.protected:
        check(ENV.protected_branches(), 'protected')
        if not ARGS.force:
            check(branches, 'local')
            remote_msg = 'remote branches on origin ' + origin
            check(remote_branches[origin], remote_msg)

    if ARGS.use_head:
        ref = 'HEAD'
        if set(branches).intersection(ARGS.branches):
            root.check_clean_workspace()
    else:
        ref = '/'.join(reference_branch.reference_branch(remote_branches))
        GIT.fetch(*(ref.split('/', maxsplit=1)))

    for new_branch in ARGS.branches:
        if new_branch in branches:
            original_id = functions.commit_id(new_branch)
            GIT.checkout(new_branch, '--quiet')
            GIT.reset('--hard', ref)
        else:
            original_id = None
            GIT.checkout('-b', new_branch, ref)

        GIT.push('-fu', origin, new_branch)
        id = functions.commit_id(new_branch)
        fmt = '+ {0}..{1} {2} -> {3}/{2}'
        PROGRAM.message(fmt.format(original_id or id, id, new_branch, origin))


def add_arguments(parser):
    add = parser.add_argument
    add('branches', nargs='+', help=_HELP_BRANCHES)
    add('-f', '--force', action='store_true', help=_HELP_FORCE)
    add('-o', '--origin', default='', help=_HELP_ORIGIN)
    add('--protected', action='store_true', help=_HELP_PROTECTED)
    add('-u', '--use-head', action='store_true', help=_HELP_USE_HEAD)
    reference_branch.add_arguments(parser)


_HELP_FORCE = 'Force push over existing branches'
_HELP_PROTECTED = 'Force push over existing or protected branches'
_HELP_ORIGIN = 'Remote origin to push to'
_HELP_USE_HEAD = 'Use HEAD and not reference branch'

if __name__ == '__main__':
    PROGRAM.start()
