# -*- coding: utf-8 -*-
#
# Copyright 2016 Continuum Analytics, Inc.
# May be copied and distributed freely only as part of an Anaconda or
# Miniconda installation.
#

"""
"""

# Standard library imports
import json
import os
import shutil
import subprocess
import sys
import uuid

# Third party imports
from qtpy.QtCore import QProcess

# Local imports
from anaconda_navigator.config.base import get_home_dir, get_conf_path
from anaconda_navigator.utils.logs import logger


def launch(project_path, command):
    """
    Handle launching commands from projects.
    """
    logger.debug(str((project_path, command)))
    command = command.format(PREFIX=project_path)
    command = command.replace('\\', '/')
    if os.name == 'nt':
        command = command.replace('/bin', '/Scripts')

    if '.ipynb' in command:
        filename = command.replace('ipython notebook ', '')
        filename = filename.replace('jupyter notebook ', '')
        run_notebook(project_path=project_path, filename=filename)
    elif command.startswith('python '):
        filename = command.replace('python ', '')
        run_python_file(project_path, filename=filename)
    else:
        proc = QProcess()
        logger.debug(command)
        proc.startDetached(command)


def console(activate=None):
    if os.name == 'nt':
        if activate:
            cmd = 'start cmd.exe /k activate ' + activate
        else:
            cmd = 'start cmd.exe'
        logger.debug(cmd)
        subprocess.Popen(cmd, shell=True)
    elif sys.platform == 'darwin':
        if activate:
            cmd = ('bash --init-file '
                   '<(echo "source activate {};")'.format(activate))
        else:
            cmd = 'bash'
        fname = os.path.join(get_conf_path(), 'a.tool')

        with open(fname, 'w') as f:
            f.write(cmd)
        os.chmod(fname, 0o777)

        logger.debug('open ' + fname)
        subprocess.call(['open ' + fname], shell=True)
    else:  # Linux, solaris, etc
        if activate:
            cmd = ['gnome-terminal', '-x', 'bash', '-c', 'bash --init-file '
                   '<(echo "source activate {};")'.format(activate)]
        else:
            cmd = ['gnome-terminal', '-e', 'bash']
        try:
            logger.debug(' '.join(cmd))
            subprocess.Popen(cmd)
            return
        except:
            pass

        if activate:
            cmd = ['xterm', '-e', 'bash --init-file '
                   '<(echo "source activate {};")'.format(activate)]
        else:
            cmd = ['xterm']
        try:
            logger.debug(' '.join(cmd))
            subprocess.Popen(cmd)
            return
        except:
            pass


def check_prog(prog, prefix=None):
    import anaconda_navigator.api.anaconda_api as api
    a = api.AnacondaAPI()
    prefix = prefix or a.conda_get_prefix_envname(name='root')
    if prog == 'notebook' or prog == 'jupyter notebook':
        pkgs = ['notebook', 'ipython-notebook', 'jupyter-notebook']
    elif prog == 'ipython' or prog == 'jupyter console':
        pkgs = ['ipython', 'jupyter_core', 'jupyter', 'jupyter_console']
    else:
        pkgs = [prog]

    return any(a.conda_package_version(prefix=prefix, pkg=p) is not None
               for p in pkgs)


def py_in_console(activate=None, prog='python'):
    """
    Run (i)python in a new console, optionally running activate first
    on the given env name/path.
    """
    logger.debug("%s, %s", activate, prog)

    if not check_prog(prog, activate):
        logger.warning('Program not available in environment: %s, %s',
                           prog, activate)
        raise RuntimeError('Program not available in environment: %s, %s',
                           prog, activate)
    if prog == 'python':
        cmd = 'python -i'
    elif prog == 'ipython' or prog == 'jupyter console':
        cmd = 'ipython -i'
    elif prog == 'notebook' or prog == 'jupyter notebook':
        cmd = 'jupyter notebook'
    if os.name == 'nt':
        if activate:
            cmd = '"activate {} & {}"'.format(activate, cmd)
        else:
            cmd = '"{}"'.format(cmd)
        logger.debug('start cmd.exe /k ' + cmd)
        subprocess.Popen('start cmd.exe /k {}'.format(cmd), shell=True)
    elif sys.platform == 'darwin':
        if activate:
            if '/' not in activate:
                out = subprocess.check_output(['conda', 'env', 'list'])
                for line in out.decode().split('\n'):
                    if line and line.split()[0] == activate:
                        activate = line.split()[-1]
                        break
            cmd = activate + '/bin/' + cmd
        else:
            cmd = cmd
        fname = os.path.join(get_conf_path(), 'a.tool')
        open(fname, 'w').write(cmd)
        os.chmod(fname, 0o777)
        logger.debug('open ' + fname)
        subprocess.call(['open ' + fname], shell=True)
    else:  # Linux, solaris, etc
        if activate:
            run_cmd = "source activate " + activate + "; " + cmd
        try:
            run_cmd = ['gnome-terminal', '-x', 'bash', '-c', cmd]
            logger.debug(' '.join(run_cmd))
            subprocess.Popen(run_cmd)
            return
        except:
            pass
        try:
            run_cmd = ['xterm', '-e', cmd]
            logger.debug(' '.join(run_cmd))
            subprocess.Popen(run_cmd)
            return
        except:
            pass


def run_ex(*args):
    """
    Start new console window, run command (given as string list).
    """
    logger.debug(str(args))
    cmd = '{0}'.format(" ".join(args))

    if os.name == 'nt':
        subprocess.Popen(['start', 'cmd.exe', '/K', cmd])

    elif sys.platform == 'darwin':
        fname = 'a.tool'
        open(fname, 'w').write(cmd)
        os.chmod(fname, 0o777)
        subprocess.call(['open ' + fname], shell=True)
        os.unlink(fname)

    else:
        terms = ['gnome-terminal', 'konsole', 'xterm']
        for term in terms:
            try:
                subprocess.Popen([term, '-e', '"{}"'.format(cmd)])
                break
            except Exception:
                pass


def run_notebook(project_path, project=None, filename=""):
    """
    Start notebook server.
    """
    from anaconda_navigator.api import AnacondaAPI
    api = AnacondaAPI()

    if project is None:
        project = api.load_project(project_path)

    kernels_folder = os.sep.join([get_home_dir(), ".ipython",
                                  "kernels"])
    display_name = '{0} ({1})'.format(project.name, project_path)
    kernel_uuid = uuid.uuid1()
    kernel_path = os.sep.join([kernels_folder, "{name}", "kernel.json"])
    pyexec = os.sep.join([project.env_prefix(project_path),
                          'bin', 'python'])
    spec = {"argv": [pyexec,
                     "-m", "IPython.kernel",
                     "-f", "{connection_file}"],
            "display_name": display_name,
            "language": "python",
            }

    # Delete any other kernel sec mathching this name!
    kernels = os.listdir(kernels_folder)
    for kernel in kernels:
        path = os.sep.join([kernels_folder, kernel])
        file_path = os.sep.join([path, 'kernel.json'])

        if os.path.isfile(file_path):
            with open(file_path, 'r') as f:
                data = json.loads(f.read())

            name = data.get('display_name', None)
            if name is not None and project_path in name:
                shutil.rmtree(path)

    os.makedirs(os.path.split(kernel_path.format(name=kernel_uuid))[0])

    with open(kernel_path.format(name=kernel_uuid), 'w') as f:
        f.write(json.dumps(spec))

    # This is not working!
    cmd = ('jupyter notebook '
           '--KernelSpecManager.whitelist={%s}' % kernel_uuid)

    cmd = ('jupyter notebook')
    command = (cmd + ' ' + filename)
    logger.debug(",".join([command, project_path]))
    subprocess.Popen(command.split(), cwd=project_path)


def run_python_file(project_path, project=None, filename=""):
    """
    Execute python in environment.
    """
    from anaconda_navigator.api import AnacondaAPI
    api = AnacondaAPI()

    if project is None:
        project = api.load_project(project_path)

    cmd = os.sep.join([project.env_prefix(project_path),
                       'bin', 'python'])
    logger.debug(",".join([cmd, filename]))
    subprocess.Popen([cmd, filename])


def run_python_console(project_path, project=None, filename=""):
    """
    Execute python in env with console.
    """
    from anaconda_navigator.api import AnacondaAPI
    api = AnacondaAPI()

    if project is None:
        project = api.load_project(project_path)

    cmd = os.sep.join([project.env_prefix(project_path),
                       'bin', 'python'])
    run_ex(cmd, filename)
