import os
from re import compile
from os.path import abspath, isdir, join
from json import loads
from subprocess import Popen, PIPE, DEVNULL, check_output, check_call
from uuid import uuid4
from textwrap import dedent
from shutil import rmtree

from ictmpl import Param, SysDep
from ictmpl.helpers.git import Git
from ictmpl.helpers.fsutil import (
    copytree_with_ignore, rmtree_without_ignore, replace_template_file)
        

__all__ = ('create_project',)


RE_LOCALDIR = compile(r'^(?:\.{1,2}/|/)')
RE_GITLINK = compile(r'^(?:git@|https?://)')

RE_COMMAND_ENV = compile(r'#!(.+)')


def ask_params(app, params=None, deep=0):
    if not params:
        return
    
    for param in params:
        if not isinstance(param, Param):
            if isinstance(param, (list, tuple)):
                app.params[param[0]] = param[1]
            continue
        
        while True:
            value = input(' '*deep*4 + param.question) or param.default
            try:
                param_value = param.strparse(value)
                app.params[param.name] = param_value
                if param.children and param_value:
                    ask_params(app, param.children, deep=deep+1)
                break
            except Exception as e:
                print(e)


def create_project(args, app):
    project_path = abspath(args.path)
    
    tmpl = args.template
    if RE_LOCALDIR.match(tmpl):
        template_path = abspath(tmpl)
        if not isdir(template_path):
            raise Exception("Template wasn't found")
        
        copytree_with_ignore(template_path, project_path)
    elif RE_GITLINK.match(tmpl):
        Git(tmpl).clone_to(project_path)
    else:
        root_repository = app.getconf('REPOSITORY', None)
        if not root_repository:
            raise Exception("Template wasn't found")
        
        Git(root_repository + tmpl).clone_to(project_path)
    
    rmtree_without_ignore(project_path)
    os.chdir(project_path)
    
    rc = {}
    try:
        with open('.ictmplrc', 'r') as file:
            exec(file.read(), rc)
    except Exception as e:
        print(e)
        return
    
    
    for key in ('name', 'version', 'description', 'author', 'author_email',
                'author_website', 'licence'):
        app.params['__{}__'.format(key.upper())] = rc.get(key, '')
    
    params = rc.get('params', [])
    if params and isinstance(params, (list, tuple)):
        print('Configure template:')
        try:
            ask_params(app, params)
        except KeyboardInterrupt:
            rmtree(project_path)
            exit()
        print('------------------\n')
    
        print('Walking files and replace params')
        templates = rc.get('templates', [])
        if templates:
            templates = map(lambda p: join(project_path, p), templates)
            for filepath in templates:
                print(filepath)
                replace_template_file(filepath, app)
        else:
            for root, dirs, files in os.walk(project_path):
                for filename in files:
                    replace_template_file(join(root, filename), app)
    
    try:
        dependencies = rc.get('sys_dependencies', [])
        if dependencies and isinstance(dependencies, (list, tuple)):
            packages = ' '.join(
                sysdep.packages 
                for sysdep in dependencies
                if isinstance(sysdep, SysDep) and sysdep.check(app)
            )
        
            if packages:
                # TODO: Need check platform
                try:
                    proc = Popen('sudo apt-get install {}'.format(packages),
                                 shell=True)
                    proc.communicate()
                except KeyboardInterrupt:
                    proc.kill()
                    print(os.linesep)
                    exit()
    except Exception as e:
        import traceback
        traceback.print_exc()
    
    setup_command = rc.get('commands', {}).get('setup', None)
    if setup_command:
        if isinstance(setup_command, (list, tuple)):
            setup_command = '\n'.join(setup_command)
        
        print('Run setup command')
        setup_command = dedent(setup_command).strip()
        env = RE_COMMAND_ENV.search(setup_command)
        if not env:
            env = '/bin/bash'
        
        env = env.group(1).strip()
        tmpfilename = '/tmp/ictmpl_%s' % uuid4().hex
        with open(tmpfilename, 'w') as file:
            file.write(setup_command)
        
        try:
            proc = Popen([env, tmpfilename], stderr=DEVNULL)
            proc.communicate()
        except KeyboardInterrupt:
            proc.kill()
            # rmtree(project_path)
        finally:
            os.remove(tmpfilename)
