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

SUMMARY = 'Amend any commit, not just the last'

HELP = """
Amend any commit in the current branch - either with another commit,
or with the contents of the staging area.
"""

EXAMPLES = """
git adjust
    Amends HEAD with the contents of the staging area.

    Equivalent to ``git commit --amend --no-edit``

git adjust HEAD~
    Amends HEAD~ with the contents of the staging area and
    then cherry-picks HEAD back on top of it

git adjust HEAD~3
    Amends HEAD~3 with the contents of the staging area, then
    cherry-picks HEAD~2, HEAD~ and HEAD back again on top of it

git adjust -m "Some message" HEAD~3
    Amends HEAD~3 with the contents of the staging area and the commit
    message "Some message", then cherry-picks HEAD~2, HEAD~ and HEAD on top

git adjust HEAD~3 --commit=HEAD~
    Amends HEAD~3 with HEAD~ and then cherry-picks HEAD~2 and HEAD
    on top of it
"""

DANGER = 'Rewrites history!'


def git_adjust():
    root.cd_root()
    if ARGS.commit:
        if ARGS.all_files or ARGS.all_tracked:
            PROGRAM.exit(_ERROR_ALL)
        root.check_clean_workspace()
    else:
        if ARGS.all_files:
            GIT.add('.')
        elif ARGS.all_tracked:
            GIT.add('-u')
        if not root.is_workspace_dirty():
            PROGRAM.exit(_ERROR_NO_COMMIT)

    functions.check_is_ancestor(ARGS.target)
    target_id = functions.commit_id(ARGS.target)

    # Create a list of commit IDS [HEAD, HEAD~, ..., target]
    ids = [functions.commit_id('HEAD')]
    while ids[-1] != target_id:
        ids.append(functions.commit_id(ids[-1] + '~'))

    if ARGS.commit:
        commit_id = functions.commit_id(ARGS.commit)
    else:

        GIT.commit('-m', '[adjust]')
        commit_id = functions.commit_id()

    GIT.reset('--hard', target_id)
    GIT.cherry_pick(commit_id)
    GIT.reset('--soft', target_id)
    if ARGS.message:
        GIT.commit('--amend', '-m', ARGS.message)
    else:
        GIT.commit('--amend', '--no-edit')

    for id in reversed(ids):
        if id == commit_id:
            continue
        if id == target_id:
            symbol = '!'
        else:
            symbol = '>'
            GIT.cherry_pick(id)
        PROGRAM.message(symbol, id, '->', *functions.commit_message())


def add_arguments(parser):
    add = parser.add_argument
    add('target', nargs='?', default='HEAD', help=_HELP_TARGET)
    add('-A', '--all-files', action='store_true', help=_HELP_ALL)
    add('-a', '--all-tracked', action='store_true', help=_HELP_ALL_TRACKED)
    add('-c', '--commit', default='', help=_HELP_COMMIT)
    add('-m', '--message', help=_HELP_MESSAGE)


_HELP_COMMIT = """\
Commit that is used to amend the target. \
If empty, use the changes in the staging area.\
"""
_HELP_ALL_TRACKED = 'Use all staged and tracked files'
_HELP_ALL = 'Use all files, even untracked ones'
_HELP_MESSAGE = 'If set, use this for the message of the amended commit'
_HELP_TARGET = 'Target commit that gets amended'

_ERROR_ALL = 'Only one of -a, -A and --commit may be used'
_ERROR_COMMIT = 'Staging area not empty, but --commit is set'
_ERROR_NO_COMMIT = 'Staging area is empty but --commit is not set'

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