#!/usr/bin/env python
import psychic_disco
import argparse
import os
import re
import sys
import subprocess
import shutil
import boto3

class Command(object):
    Name = ""
    Help = ""

    @staticmethod
    def command(args):
        return NotImplemented
    
    @staticmethod
    def configure_parser(parser):
        return NotImplemented

class ListEntrypoints(Command):
    Name = "list_entrypoints"
    Help = "list all entrypoints for a given module"
    @staticmethod
    def configure_parser(parser):
        parser.add_argument('module_name')

    @staticmethod
    def command(args):
        psychic_disco.attempt_import(args.module_name)
        print psychic_disco.entry_points()

class DiscoverEntrypoints(Command):
    Name = "discover_entrypoints"
    Help = "search repo for possible entrypoints"
    @staticmethod
    def configure_parser(parser):
        pass

    @staticmethod
    def command(args):
        psychic_disco.discover_entrypoints(args.repo)
        print psychic_disco.entry_points()

class DeployLambdas(Command):
    Name = "deploy_lambdas"
    Help = "Deploy the defined lambda functions"
    @staticmethod
    def configure_parser(parser):
        pass

    @staticmethod
    def command(args):
        psychic_disco.discover_entrypoints(args.repo)
        for ep in psychic_disco.entry_points():
            function_name = "psychic_disco-%s" % (ep['full_name'].replace('.','-'))
            argv = ['aws','lambda','create-function','--function-name',function_name,'--runtime','python2.7','--role',psychic_disco.config.default_iam_role,'--handler',ep['full_name'],'--code',"S3Bucket=%s,S3Key=deployment-package.zip" % psychic_disco.config.default_s3_bucket]
            print "==> %s" % " ".join(argv)
            subprocess.call(argv)

class BundleApplication(Command):
    Name = "bundle"
    Help = "Bundle application into a Lambda-friendly deployment package"
    @staticmethod
    def configure_parser(parser):
        pass

    @staticmethod
    def command(args):
        bundle_dir = os.path.join(args.repo,".psychic_disco") 
        if not os.path.exists(bundle_dir):
            os.mkdir(bundle_dir)
        os.environ['LC_ALL'] = 'C'
        subprocess.call(['virtualenv',bundle_dir])
        virtualenv_activate = os.path.join(bundle_dir,"bin/activate")
        requirements_file = os.path.join(args.repo, "requirements.txt")
        subprocess.call(['bash','-c',"source %s; pip install -r %s; deactivate" % (virtualenv_activate, requirements_file)])
        # Copy everything in
        dist_packages = os.path.join(bundle_dir,"lib/python2.7/dist-packages")
        for (dirpath, dirnames, filenames) in os.walk(args.repo):
            for dirname in dirnames:
                if dirname.startswith("."):
                    dirnames.remove(dirname) # Don't visit hidden directories
            for filename in filenames:
                if filename.endswith(".py") and not filename.startswith("."): # Don't mess with hidden files
                    relative_path = os.path.join(dirpath, filename)
                    dest_path = os.path.join(dist_packages, relative_path)
                    print "cp %s %s" % (relative_path, dest_path)
                    subprocess.call(['cp',relative_path,dest_path])
        os.chdir(dist_packages)
        subprocess.call(['zip','-r', 'deployment-package.zip','.','-i','*'])
        subprocess.call(['aws','s3', 'cp', 'deployment-package.zip', psychic_disco.conf.default_s3_bucket])


def build_parser():
    parser = argparse.ArgumentParser(prog='psychic_disco')
    parser.add_argument('--repo', help='microservices repo', default=".")
    parser.add_argument('--config', help='config file', default="psychic_disco_config.py")
    subparsers = parser.add_subparsers(help='sub-command help')
    for subcommand in Command.__subclasses__():
        subparser = subparsers.add_parser(subcommand.Name, help=subcommand.Help)
        subcommand.configure_parser(subparser)
        subparser.set_defaults(func=subcommand.command)
    return parser

if __name__ == "__main__":
    parser = build_parser()
    args = parser.parse_args()
    sys.path[0] = args.repo
    if os.path.exists(args.config):
        config_module = psychic_disco.convert_path_to_module(args.config)
        psychic_disco.attempt_import(config_module)
    args.func(args)
