#!/usr/bin/env python3
from gitz import git_functions
from gitz.program import PROGRAM
from gitz.program import git
from gitz.program import safe_git
import os

SUMMARY = 'Split a range of commits into many single-file commits'
USAGE = 'git-split [<pathspec>]'
DANGER = 'Rewrites history!'
HELP = """
`git-split` squashes together a range of commits and the staging area, then
splits out a sequence of individual commits, one for each file changed.
"""
EXAMPLES = """
git-split
    Splits the staging area if it's not empty, otherwise HEAD

git-split HEAD
    Splits the squash of the staging area and HEAD

git-split HEAD~
    Splits the squash of the staging area, HEAD and HEAD~
"""


def git_split():
    git_functions.check_git()
    os.chdir(git_functions.find_git_root())
    not_added = []

    for line in safe_git.status('--porcelain'):
        mode, filenames = line.split(maxsplit=1)
        if mode == '??':
            not_added.append(filenames)

    if PROGRAM.args.commit:
        commit = PROGRAM.args.commit + '~'
    elif git_functions.is_workspace_dirty():
        commit = 'HEAD'
    else:
        commit = 'HEAD~'

    commit = git_functions.commit_id(commit)
    git.reset('--soft', commit)
    lines = safe_git.status('--porcelain')

    git.reset(commit)
    commit_count = 0

    for line in lines:
        mode, filenames = line.split(maxsplit=1)
        filenames_split = filenames.split(' -> ')
        mode = mode.strip()
        if mode == '??':
            if filenames in not_added:
                continue
            mode = 'R' if len(filenames_split) > 1 else 'A'
        mode_name = NAMES[mode[0]]

        # Renaming is a special case with two files on a line
        # separated by -> and with mode = '??'
        try:
            git.add(*filenames_split)
            git.commit('-m', '[split] %s %s' % (mode_name, filenames))
            commit_count += 1

        except Exception:
            PROGRAM.error("couldn't commit filenames", filenames)

    s = '' if commit_count == 1 else 's'
    print('%d commit%s generated' % (commit_count, s))


def add_arguments(parser):
    parser.add_argument('commit', nargs='?', default='', help=_HELP_COMMIT)


NAMES = 'Added', 'Deleted', 'Modified', 'Renamed'
NAMES = {name[0]: name for name in NAMES}
_HELP_COMMIT = 'Optional commit ID to split from'


if __name__ == '__main__':
    PROGRAM.ALLOW_NO_RUN = False
    PROGRAM.start(**globals())
