#!/usr/bin/python
# PYTHON_ARGCOMPLETE_OK

import argparse
import argcomplete
import os
import json
import inspect
import sys
import logging

from voidpp_tools.json_encoder import JsonEncoder

from vcp import VCP
from vcp.exceptions import ProjectException, RepositoryException
from vcp.colors import Colors
from vcp.cli_arguments_tree_parser import CLIArgumentsTreeParser

class ColoredFormatter(logging.Formatter):
    def format(self, record):
        colors = {
            logging.ERROR: Colors.red,
            logging.WARNING: Colors.yellow,
            logging.INFO: Colors.default,
        }

        return colors.get(record.levelno, Colors.default) + record.getMessage() + Colors.default

logger_handler = logging.StreamHandler(sys.stdout)
logger_handler.setFormatter(ColoredFormatter())
logging.root.addHandler(logger_handler)
logging.root.setLevel(logging.INFO)
logging.raiseExceptions = True

logger = logging.getLogger('vcp')

vcp = VCP()

project_names = vcp.projects.keys()
repository_names = vcp.repositories.keys()

project_mod_subcommands = []

for name in vcp.projects:
    project = vcp.projects[name]
    appendable_repos = list(set(repository_names) - set(project.repositories))
    project_mod_subcommands.append(
        dict(
            name = name,
            desc = dict(),
            subcommands = [
                dict(
                    name = 'repository',
                    desc = dict(),
                    subcommands = [
                        dict(
                            name = 'add',
                            desc = dict(help = 'Add repo'),
                            arguments = [
                                dict(arg_name = 'names', help = 'repo names', nargs = '*', choices = appendable_repos),
                            ]
                        ),
                        dict(
                            name = 'remove',
                            desc = dict(help = 'Remove repo'),
                            arguments = [
                                dict(arg_name = 'names', help = 'repo names', nargs = '*', choices = project.repositories),
                            ]
                        ),
                        dict(
                            name = 'clear',
                            desc = dict(help = 'Remove all repo from project'),
                        ),
                    ],
                ),
                dict(
                    name = 'description',
                    desc = dict(help = 'Set project description'),
                    arguments = [
                        dict(arg_name = 'data'),
                    ]
                ),
            ],
        )
    )

# NOTE: project name parameter added later!
project_action_commands = [
    dict(
        name = 'status',
        desc = dict(help = 'Project status'),
    ),
    dict(
        name = 'cmd',
        desc = dict(help = 'Execute a command on a project (all repos)'),
        arguments = [
            dict(arg_name = 'command', help = 'command and params'),
        ]
    ),
    dict(
        name = 'untracked',
        desc = dict(help = 'Untracked files'),
    ),
    dict(
        name = 'dirty',
        desc = dict(help = 'Dirty files (list of untracked or modified files)'),
    ),
    dict(
        name = 'pushables',
        desc = dict(help = 'Show all unpushed local commits'),
        arguments = [
            dict(arg_name = '--remote', help = 'remote name', default = 'origin/master')
        ]
    ),
    dict(
        name = 'fetch',
        desc = dict(help = 'Fetch repositories'),
    ),
    dict(
        name = 'news',
        desc = dict(help = 'Project news'),
        arguments = [
            dict(arg_name = ['--fromcache', '-c'], help = 'does not do fetch before the check', action = 'store_true'),
        ]
    ),
    dict(
        name = 'diff',
        desc = dict(help = 'Show diff in all repositories'),
    ),
]

manager_commands = [
    dict(
        name = 'project',
        desc = dict(help = 'Project manager commands'),
        subcommands = [
            dict(
                name = 'create',
                desc = dict(help = 'Create project'),
                arguments = [
                    dict(arg_name = 'name', help = 'project name'),
                    dict(arg_name = '--description', default = '', help = 'project description'),
                    dict(arg_name = '--repositories', nargs = '*', choices = repository_names, default = [], help = 'project repos'),
                    dict(arg_name = '--default', help = 'make this project default', action = 'store_true'),
                ]
            ),
            dict(
                name = 'remove',
                desc = dict(help = 'Remove project'),
                arguments = [
                    dict(arg_name = 'name', help = 'project name', choices = project_names),
                ]
            ),
            dict(
                name = 'show',
                desc = dict(help = 'Remove project'),
                arguments = [
                    dict(arg_name = 'name', help = 'project name', choices = project_names),
                ]
            ),
            dict(
                name = 'list',
                desc = dict(help = 'List of projects'),
            ),
            dict(
                name = 'modify',
                desc = dict(help = 'Modify project'),
                subcommands = project_mod_subcommands,
            ),
            dict(
                name = 'default',
                desc = dict(help = 'Set project for default. If default project is specified, the \'project\' parameter in the generic commands is optional'),
                arguments = [
                    dict(arg_name = 'name', help = 'project name', choices = project_names),
                ]
            ),
        ]
    ),
    dict(
        name = 'repository',
        desc = dict(help = 'Repository manager commands'),
        subcommands = [
            dict(
                name = 'create',
                desc = dict(help = 'Create repository'),
                arguments = [
                    dict(arg_name = 'path', help = 'Repository path'),
                    dict(arg_name = '--name', help = 'Repository name. Default: repo dir name', default = None),
                    dict(arg_name = '--type', help = 'Repository type', choices = ['git'], default = 'git'),
                    dict(arg_name = '--add-to', help = 'add to projects', choices = project_names, nargs = '*'),
                ]
            ),
            dict(
                name = 'cmd',
                desc = dict(help = 'Execute a command on a repository'),
                arguments = [
                    dict(arg_name = 'name', help = 'repository name', choices = repository_names),
                    dict(arg_name = 'command', help = 'command and params'),
                ]
            ),
            dict(
                name = 'remove',
                desc = dict(help = 'Remove repository'),
                arguments = [
                    dict(arg_name = 'name', help = 'repository name', choices = repository_names),
                ]
            ),
            dict(
                name = 'list',
                desc = dict(help = 'List of repositories'),
            ),
        ]
    ),
    dict(
        name = 'version',
        desc = dict(help = 'Show VCP version'),
    ),
]

# add project name parameter for project_action_commands
for command in project_action_commands:
    project_param = dict(arg_name = 'name', help = 'project name', choices = project_names)
    if vcp.default_project is not None and vcp.default_project in project_names:
        project_param.update(nargs = '?', default = vcp.default_project)
    if 'arguments' not in command:
        command['arguments'] = []
    command['arguments'].insert(0, project_param)
    command['arguments'].append(dict(arg_name = '--list', help = 'Print only repo names', action = 'store_true'))

vcp.action_commands_lookup(project_action_commands)

parser = CLIArgumentsTreeParser(project_action_commands + manager_commands, 'vcp', argparse.ArgumentParser())
parser.build()
argcomplete.autocomplete(parser.parser, exclude = ['-h', '--help'])
data = parser.parse()

def fetch(arg_data, handler):
    if 'sub' in arg_data:
        fetch(arg_data['sub'], getattr(handler, arg_data.name)())
    elif 'args' in arg_data:
        getattr(handler, arg_data.name)(**arg_data['args'])
    else:
        getattr(handler, arg_data.name)()

try:
    fetch(data['sub'], vcp)
except Exception as e:
    raise
