#!/usr/bin/env python

""" Command-line interface to various NSoT administrative commands."""

import alembic.config
import alembic.command
import argparse
import BaseHTTPServer
import code
import getpass
import logging
from mrproxy import UserProxyHandler
from pprint import pprint

import nsot
from nsot import models
from nsot.settings import settings
from nsot.util import get_loglevel


sa_log = logging.getLogger("sqlalchemy.engine.base.Engine")


def make_session():
    db_engine = models.get_db_engine(settings["database"])
    models.Session.configure(bind=db_engine)
    return models.Session()


def setup_migration_config():
    config = alembic.config.Config()
    config.set_main_option("script_location", "nsot:migrations")
    config.set_main_option("sqlalchemy.url", settings["database"])
    return config


def migrations_latest_command(args):
    print "Upgrading to latest revision...",
    config = setup_migration_config()
    try:
        alembic.command.upgrade(config, "head")
        print "Done"
    except alembic.util.CommandError as err:
        print "Failed ({})".format(err)


def migrations_upgrade_command(args):
    print "Upgrading to revision {}...".format(args.revision),
    config = setup_migration_config()
    try:
        alembic.command.upgrade(config, args.revision)
        print "Done"
    except alembic.util.CommandError as err:
        print "Failed ({})".format(err)


def migrations_downgrade_command(args):
    print "Downgrading to revision {}...".format(args.revision),
    config = setup_migration_config()
    try:
        alembic.command.downgrade(config, args.revision)
        print "Done"
    except alembic.util.CommandError as err:
        print "Failed ({})".format(err)


def migrations_revision_command(args):
    print "Generating New Revision...",
    config = setup_migration_config()
    try:
        alembic.command.revision(config, autogenerate=True)
        print "Done"
    except alembic.util.CommandError as err:
        print "Failed ({})".format(err)


def user_proxy_command(args):
    class ServerArgs(object):
        def __init__(self, backend_port, username):
            self.backend_port = backend_port
            self.header = ["X-NSoT-Email: %s" % username]

    username = args.username
    if username is None:
        username = getpass.getuser()
        logging.debug("No username provided, using (%s)", username)
    username += "@localhost"

    server = BaseHTTPServer.HTTPServer(
        ('localhost', args.listen_port), UserProxyHandler
    )
    server.args = ServerArgs(args.backend_port, username)
    try:
        logging.info(
            "Starting user_proxy on port (%s) with user (%s)",
            args.listen_port, username
        )
        server.serve_forever()
    except KeyboardInterrupt:
        print "Bye!"


def shell_command(args):
    session = make_session()
    code.interact(local={
        "session": session,
        "m": models,
        "models": models,
        "pp": pprint,
    })


def main():

    description_msg = "NSoT Control"
    parser = argparse.ArgumentParser(description=description_msg)

    parser.add_argument("-c", "--config", default="/etc/nsot.yaml",
                        help="Path to config file.")
    parser.add_argument("-v", "--verbose", action="count", default=0, help="Increase logging verbosity.")
    parser.add_argument("-q", "--quiet", action="count", default=0, help="Decrease logging verbosity.")
    parser.add_argument("-V", "--version", action="version",
                        version="%%(prog)s %s" % nsot.__version__,
                        help="Display version information.")


    subparsers = parser.add_subparsers(dest="command")

    # Migration Parsers
    migrations_parser = subparsers.add_parser(
        "migrations", help="Create and apply database migrations.")
    migrations_subparsers = migrations_parser.add_subparsers(
        dest="migratrions_command"
    )

    migrations_latest_parser = migrations_subparsers.add_parser("latest")
    migrations_latest_parser.set_defaults(func=migrations_latest_command)

    migrations_upgrade_parser = migrations_subparsers.add_parser("upgrade")
    migrations_upgrade_parser.add_argument("revision")
    migrations_upgrade_parser.set_defaults(func=migrations_upgrade_command)

    migrations_downgrade_parser = migrations_subparsers.add_parser("downgrade")
    migrations_downgrade_parser.add_argument("revision")
    migrations_downgrade_parser.set_defaults(func=migrations_downgrade_command)

    migrations_revision_parser = migrations_subparsers.add_parser("revision")
    migrations_revision_parser.set_defaults(func=migrations_revision_command)

    # User Proxy Parsers
    user_proxy_parser = subparsers.add_parser("user_proxy", help="Start a development reverse proxy.")
    user_proxy_parser.set_defaults(func=user_proxy_command)
    user_proxy_parser.add_argument("-p", "--listen-port", default=8888, type=int,
                                   help="Port to listen on.")
    user_proxy_parser.add_argument("-P", "--backend-port", default=8990, type=int,
                                   help="Port to proxy to.")
    user_proxy_parser.add_argument("username", nargs="?", default=None)

    # Shell Parsers
    shell_parser = subparsers.add_parser("shell", help="Launch a shell with models imported.")
    shell_parser.set_defaults(func=shell_command)

    args = parser.parse_args()
    settings.update_from_config(args.config)

    log_level = get_loglevel(args)
    logging.basicConfig(
        level=log_level,
        format=settings.log_format,
    )

    if log_level < 0:
        sa_log.setLevel(logging.INFO)

    args.func(args)

if __name__ == "__main__":
    main()
