"""nginx sites

Usage:
  nginx-sites ls
  nginx-sites enable <name>
  nginx-sites disable <name>
  nginx-sites new <name> [--root=<path>] [--template=<template>] [(--port=<port>)...]
  nginx-sites rm <name>
  nginx-sites open <name>
  nginx-sites cp <source> <target>
  nginx-sites reload
  nginx-sites config [-e] [-i]
  nginx-sites --version

Options:
  -h --help             Show this screen.
  --version             Show version.
  --template=<template> specify a template [default: php].
  --root=<path>         specify root default is pwd.

Examples:
    nginx-sites new nodejs.test --template=node --port=3003 --port=3004
    nginx-sites new phpfpm.test --template=php --port=9000
"""

import os
import sys
import time
import tempfile
import readline
import json
from subprocess import call
from subprocess import check_output
import pkg_resources
import shutil
from docopt import docopt
from pystache import render

from .colorize import formatter

config_path = '~/.nginx-sites.json'


class NginxSites:
    def __init__(self, config):
        self.config = config

    def enabled_conf(self, name=None):
        if name is None:
            return self.config['sites_enabled']
        return os.path.join(self.config['sites_enabled'], name)

    def available_conf(self, name=None):
        if name is None:
            return self.config['sites_available']
        return os.path.join(self.config['sites_available'], name)

    def new(self, server_name, root, template, port):
        if port is not None:
            port = [{'port': p} for p in port]
        with open(self.available_conf(server_name), 'w') as fp:
            template_path = os.path.join(self.config['templates_path'],
                                         template + '.conf')
            with open(template_path, 'r') as tmpl:
                fp.write(render(tmpl.read(), locals()))
                self.enable(server_name)

    def rm(self, name):
        self.disable(name)
        if os.path.exists(self.available_conf(name)):
            os.remove(self.available_conf(name))

    def ls(self):
        walker = os.walk(self.enabled_conf())
        _, _, enabled_sites = next(walker)
        walker = os.walk(self.available_conf())
        _, _, available_sites = next(walker)
        print(formatter('green')('enabled sites:'))
        sys.stdout.writelines(['  %s\n' % site for site in enabled_sites
                               if site in available_sites])
        print(formatter('yellow')('available sites:'))
        sys.stdout.writelines(['  %s\n' % site for site in available_sites
                               if site not in enabled_sites])
        print(formatter('red')('active sites:'))
        sys.stdout.writelines(['  %s\n' % site for site in enabled_sites
                               if site not in available_sites])

    def enable(self, name):
        if os.path.exists(self.enabled_conf(name)):
            os.remove(self.enabled_conf(name))
        os.symlink(self.available_conf(name), self.enabled_conf(name))

    def disable(self, name):
        if os.path.exists(self.enabled_conf(name)):
            os.remove(self.enabled_conf(name))

    def cp(self, source, target):
        if os.path.exists(self.available_conf(source)):
            shutil.copy2(self.available_conf(source),
                         self.available_conf(target))
            self.open(target)
        else:
            print("%s not exists" % self.available_conf(source))

    def open(self, name):
        editor = os.environ.get('EDITOR', 'vi')
        call([editor, self.available_conf(name)])

    def reload(self):
        call([self.config['nginx_bin'], '-s', 'reload'])


def editconf(path):
    editor = os.environ.get('EDITOR', 'vi')
    f = tempfile.NamedTemporaryFile(delete=False)
    f.close()
    if(os.path.exists(path)):
        shutil.copyfile(path, f.name)
    ret = call([editor, f.name])
    if ret is 0:
        try:
            with open(f.name) as fp:
                json.load(fp)
            shutil.copyfile(f.name, path)
        except ValueError:
            print('not valid json')
        except:
            print('config failed!')


def load_config(path):
    if os.path.exists(path):
        try:
            with open(path) as fp:
                return json.load(fp)
        except ValueError:
            print('config file is not valid json')
            time.sleep(2)
            editconf(path)
            return load_config(path)
        except:
            print('failed to load config from %s' % path)


def dump_config(path, config):
    with open(path, 'w') as fp:
        json.dump(config, fp, indent=True)


def get_input(prompt, prefill=''):
    readline.set_startup_hook(lambda: readline.insert_text(prefill))
    try:
        return raw_input(prompt)
    finally:
        readline.set_startup_hook()


def config_interactively():
    ret = {}
    ret['sites_enabled'] = get_input('path to sites-enabled: ',
                                     '/etc/nginx/sites-enabled')
    ret['sites_available'] = get_input('path to sites-available: ',
                                       ret['sites_enabled'].replace('enabled', 'available'))
    try:
        nginx_bin = check_output(['which', 'nginx']).strip()
    except:
        nginx_bin = ''
    ret['nginx_bin'] = get_input('path to nginx executable: ', nginx_bin)
    dist = pkg_resources.get_distribution('nginx_sites')
    ret['templates_path'] = os.path.join(dist.location,
                                         'nginx_sites', 'templates')
    return ret


def main():
    config_path_full = os.path.expanduser(config_path)
    config = load_config(config_path_full)

    if config is None:
        print('config file not loaded!')
        config = config_interactively()
        dump_config(config_path_full, config)

    args = docopt(__doc__, version='nginx-sites 0.1.0')
    sites = NginxSites(config)
    try:
        if args['ls']:
            sites.ls()
        elif args['enable']:
            sites.enable(args['<name>'])
        elif args['disable']:
            sites.disable(args['<name>'])
        elif args['new']:
            root = os.getcwd() if args['--root'] is None else args['--root']
            template = args['--template'] or 'php'  # TODO docstring parsed incorrectly
            sites.new(args['<name>'], root, template, args['--port'])
        elif args['rm']:
            sites.rm(args['<name>'])
        elif args['cp']:
            sites.cp(args['<source>'], args['<target>'])
        elif args['open']:
            sites.open(args['<name>'])
        elif args['config']:
            if args['-e']:
                editconf(config_path_full)
            elif args['-i']:
                config = config_interactively()
                dump_config(config_path_full, config)
            else:
                print(json.dumps(load_config(config_path_full), indent=2))
        elif args['reload']:
            sites.reload()
    except OSError, e:
        print(e)

if __name__ == '__main__':
    main()
