#!/usr/bin/env python

"""
Thin wrapper around the "aws" command line interface (CLI) for use
with LocalStack.

The "awslocal" CLI allows you to easily interact with your local services
without having to specify "--endpoint-url=http://..." for every single command.

Example:
Instead of the following command ...
aws --endpoint-url=https://localhost:4568 --no-verify-ssl kinesis list-streams
... you can simply use this:
awslocal kinesis list-streams

Options:
  Run "aws help" for more details on the aws CLI subcommands.
"""

import os
import sys
import subprocess
from threading import Thread

PARENT_FOLDER = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
if os.path.isdir(os.path.join(PARENT_FOLDER, '.venv')):
    sys.path.insert(0, PARENT_FOLDER)

from localstack_client import config  # noqa: E402


def get_service():
    for param in sys.argv[1:]:
        if not param.startswith('-'):
            return param


def get_service_endpoint(localstack_host=None):
    service = get_service()
    if service == 's3api':
        service = 's3'
    endpoints = config.get_service_endpoints(localstack_host=localstack_host)
    return endpoints.get(service)


def usage():
    print(__doc__.strip())


def run(cmd, env={}):

    def output_reader(pipe, out):
        out_binary = os.fdopen(out.fileno(), 'wb')
        with pipe:
            for line in iter(pipe.readline, b''):
                out_binary.write(line)
                out_binary.flush()

    process = subprocess.Popen(
        cmd, env=env,
        stderr=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE)

    Thread(target=output_reader, args=[process.stdout, sys.stdout]).start()
    Thread(target=output_reader, args=[process.stderr, sys.stderr]).start()

    process.wait()
    sys.exit(process.returncode)


def main():
    if len(sys.argv) > 1 and sys.argv[1] == '-h':
        return usage()
    try:
        import awscli.clidriver  # noqa: F401
    except Exception:
        return run_as_separate_process()
    run_in_process()


def prepare_environment():

    # prepare env vars
    env_dict = os.environ.copy()
    env_dict['PYTHONWARNINGS'] = os.environ.get(
        'PYTHONWARNINGS', 'ignore:Unverified HTTPS request')
    env_dict['AWS_DEFAULT_REGION'] = os.environ.get(
        'AWS_DEFAULT_REGION', 'us-east-1')
    env_dict['AWS_ACCESS_KEY_ID'] = os.environ.get(
        'AWS_ACCESS_KEY_ID', '_not_needed_locally_')
    env_dict['AWS_SECRET_ACCESS_KEY'] = os.environ.get(
        'AWS_SECRET_ACCESS_KEY', '_not_needed_locally_')

    # update environment variables in the current process
    os.environ.update(env_dict)

    return env_dict


def prepare_cmd_args():
    # get service and endpoint
    localstack_host = os.environ.get('LOCALSTACK_HOST')
    endpoint = get_service_endpoint(localstack_host=localstack_host)
    service = get_service()
    if not endpoint and service and service != 'help':
        msg = 'Unable to find LocalStack endpoint for service "%s"' % service
        print('ERROR: %s' % msg)
        return sys.exit(1)

    # prepare cmd args
    cmd_args = sys.argv
    if endpoint:
        cmd_args.insert(1, '--endpoint-url=%s' % endpoint)
        if 'https' in endpoint:
            cmd_args.insert(2, '--no-verify-ssl')
    return list(cmd_args)


def run_as_separate_process():
    """
    Constructs a command line string and calls "aws" as an external process.
    """
    env_dict = prepare_environment()
    cmd_args = prepare_cmd_args()
    cmd_args[0] = 'aws'
    # run the command
    run(cmd_args, env_dict)


def run_in_process():
    """
    Modifies the command line args in sys.argv and calls the AWS cli
    method directly in this process.
    """
    import awscli.clidriver
    if os.environ.get('LC_CTYPE', '') == 'UTF-8':
        os.environ['LC_CTYPE'] = 'en_US.UTF-8'
    prepare_environment()
    prepare_cmd_args()
    sys.exit(awscli.clidriver.main())


if __name__ == '__main__':
    main()
