#!/usr/bin/python

import argparse
import getpass
import logging
import os
import sys

dir = os.path.split(os.path.dirname(__file__))[-1]
if dir == 'scripts':
    sys.path.append(os.path.join(dir, '..'))

from prvsnlib.packager import Packager
from prvsnlib.provisioner import Provisioner
from prvsnlib.runbook import Runbook
from prvsnlib.utils.ssh import Ssh

from prvsnlib.utils.validation import (
    validate_runbook,
    validate_roles,
    validate_hostname,
    validate_username,
)


def main():
    parser = argparse.ArgumentParser(description='Simple machine provisioning tool.')
    parser.add_argument('-b', '--runbook', action='store', default='.', help='Path to the runbook (default: .)')
    parser.add_argument('-n', '--hostname', action='store', default=None, help='Remote hostname (default: localhost)')
    parser.add_argument('-o', '--output', action='store', default='package.pyz', help='Package output file')
    parser.add_argument('-r', '--roles', action='store', default='', help='Roles to provision, comma-separated (default: none)')
    parser.add_argument('-s', '--sudo', action='store_true', help='Run provisioning as root (default: logged in user)')
    parser.add_argument('-u', '--username', action='store', default=getpass.getuser(), help='Remote username (default: current user)')
    parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')

    parser.add_argument('--no-copy-keys', action='store_true', help='Do not copy public ssh keys to remote (default: copy)')

    parser.add_argument('command', nargs='?', default=None, help="Command: provision(default), init, package, remote")
    args = parser.parse_args()

    if args.verbose:
        logging.root.setLevel(logging.DEBUG)
    else:
        logging.root.setLevel(logging.INFO)

    if not args.command:
        if args.hostname:
            args.command = 'remote'
        else:
            args.command = 'provision'

    if args.command == 'remote' and not args.hostname:
        args.hostname = 'localhost'

    if args.command == 'init':
        Runbook('runbook', args.runbook).create_scaffolding()

    elif args.command == 'package':
        runbook = Runbook('runbook', args.runbook)

        validate_runbook(runbook)
        validate_roles(runbook, args.roles)

        Packager(
            runbook,
            roles=args.roles.split(','),
            dest=args.output,
        ).build_package()

    elif args.command == 'provision':

        if args.sudo:
            if os.geteuid() != 0:
                if sys.stdout.isatty():
                    os.execvp('sudo', ['sudo', '-p "sudo password"'] + sys.argv)
                else:
                    logging.warning('Cannot sudo; not a tty. Running as user "' + getpass.getuser() + '"')

        runbook = Runbook('runbook', args.runbook)

        validate_runbook(runbook)
        validate_roles(runbook, args.roles)

        Provisioner(
            runbook,
            args.roles.split(','),
        ).run()
    elif args.command == 'remote':

        runbook = Runbook('runbook', args.runbook)

        validate_runbook(runbook)
        validate_roles(runbook, args.roles)
        validate_hostname(args.hostname)

        pkg = Packager(
            runbook,
            roles=args.roles.split(','),
            dest=args.output,
        ).build_package()

        ssh = Ssh(remote=args.hostname, user=args.username)

        if not args.no_copy_keys:
            ssh.copy_public_keys()

        dest = 'package.pyz'

        logging.header('Sending package to ' + ssh.remote)
        out, err = ssh.copyTo(pkg, dest)
        if err:
            logging.error('Sending package failed.')
            sys.exit(1)
        logging.success('Sent.')

        logging.header('Remotely executing package on ' + ssh.remote)
        out, err = ssh.command(['python', dest], log_output=logging.info, sudo=args.sudo)
        if err:
            logging.error('Remotely executing package failed.')
            sys.exit(1)
        logging.success('Executed.')

    else:
        logging.error('Invalid command.')
        sys.exit(1)

if __name__ == "__main__":
    main()