#!/usr/bin/env python

"""
Thin wrapper around the "pulumi" command line interface (CLI) to use
Pulumi (https://pulumi.com) with LocalStack (https://localstack.cloud).

Options:
  Run "pulumi -h" for more details on the pulumi CLI subcommands.
"""

import os
import sys
import yaml

# for local testing
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)

# define global constants
TRUE_STRINGS = ['1', 'true', 'True']
PULUMI_CMD = os.environ.get('PULUMI_CMD') or 'pulumi'
PULUMI_STACK_NAME = os.environ.get('PULUMI_STACK_NAME') or 'localstack'
LOCALSTACK_HOSTNAME = os.environ.get('LOCALSTACK_HOSTNAME') or 'localhost'
EDGE_PORT = int(os.environ.get('EDGE_PORT') or '4566')
USE_SSL = os.environ.get('USE_SSL') in TRUE_STRINGS

DEFAULT_CONFIG = {
    'config': {
        'aws:accessKey': 'test',
        'aws:secretKey': 'test',
        'aws:endpoints': [],
        'aws:region': 'us-east-1',
        'aws:s3ForcePathStyle': 'true',
        'aws:skipCredentialsValidation': 'true',
        'aws:skipRequestingAccountId': 'true',
    }
}

# Unfortunately, we need to hardcode the service names here, as importing from
# localstack-client doesn't work (some keys differ / are unavailable in Pulumi)
SERVICES = [
    'accessanalyzer',
    'account',
    'acm',
    'acmpca',
    'alexaforbusiness',
    'amp',
    'amplify',
    'amplifybackend',
    'apigateway',
    'apigatewayv2',
    'appautoscaling',
    'appconfig',
    'appflow',
    'appintegrations',
    'appintegrationsservice',
    'applicationautoscaling',
    'applicationcostprofiler',
    'applicationdiscovery',
    'applicationdiscoveryservice',
    'applicationinsights',
    'appmesh',
    'appregistry',
    'apprunner',
    'appstream',
    'appsync',
    'athena',
    'auditmanager',
    'augmentedairuntime',
    'autoscaling',
    'autoscalingplans',
    'backup',
    'batch',
    'braket',
    'budgets',
    'chime',
    'cloud9',
    'cloudcontrol',
    'cloudcontrolapi',
    'clouddirectory',
    'cloudformation',
    'cloudfront',
    'cloudhsm',
    'cloudhsmv2',
    'cloudsearch',
    'cloudsearchdomain',
    'cloudtrail',
    'cloudwatch',
    'cloudwatchevents',
    'cloudwatchlogs',
    'codeartifact',
    'codebuild',
    'codecommit',
    'codedeploy',
    'codeguruprofiler',
    'codegurureviewer',
    'codepipeline',
    'codestar',
    'codestarconnections',
    'codestarnotifications',
    'cognitoidentity',
    'cognitoidentityprovider',
    'cognitoidp',
    'cognitosync',
    'comprehend',
    'comprehendmedical',
    'config',
    'configservice',
    'connect',
    'connectcontactlens',
    'connectparticipant',
    'costandusagereportservice',
    'costexplorer',
    'cur',
    'databasemigration',
    'databasemigrationservice',
    'dataexchange',
    'datapipeline',
    'datasync',
    'dax',
    'detective',
    'devicefarm',
    'devopsguru',
    'directconnect',
    'dlm',
    'dms',
    'docdb',
    'ds',
    'dynamodb',
    'dynamodbstreams',
    'ec2',
    'ec2instanceconnect',
    'ecr',
    'ecrpublic',
    'ecs',
    'efs',
    'eks',
    'elasticache',
    'elasticbeanstalk',
    'elasticinference',
    'elasticsearch',
    'elasticsearchservice',
    'elastictranscoder',
    'elb',
    'elbv2',
    'emr',
    'emrcontainers',
    'es',
    'eventbridge',
    'events',
    'finspace',
    'finspacedata',
    'firehose',
    'fis',
    'fms',
    'forecast',
    'forecastquery',
    'forecastqueryservice',
    'forecastservice',
    'frauddetector',
    'fsx',
    'gamelift',
    'glacier',
    'globalaccelerator',
    'glue',
    'gluedatabrew',
    'greengrass',
    'greengrassv2',
    'groundstation',
    'guardduty',
    'health',
    'healthlake',
    'honeycode',
    'iam',
    'identitystore',
    'imagebuilder',
    'inspector',
    'iot',
    'iot1clickdevices',
    'iot1clickdevicesservice',
    'iot1clickprojects',
    'iotanalytics',
    'iotdataplane',
    'iotdeviceadvisor',
    'iotevents',
    'ioteventsdata',
    'iotfleethub',
    'iotjobsdataplane',
    'iotsecuretunneling',
    'iotsitewise',
    'iotthingsgraph',
    'iotwireless',
    'kafka',
    'kafkaconnect',
    'kendra',
    'kinesis',
    'kinesisanalytics',
    'kinesisanalyticsv2',
    'kinesisvideo',
    'kinesisvideoarchivedmedia',
    'kinesisvideomedia',
    'kinesisvideosignalingchannels',
    'kms',
    'lakeformation',
    'lambda',
    'lexmodelbuilding',
    'lexmodelbuildingservice',
    'lexmodels',
    'lexmodelsv2',
    'lexruntime',
    'lexruntimeservice',
    'lexruntimev2',
    'licensemanager',
    'lightsail',
    'location',
    'lookoutequipment',
    'lookoutforvision',
    'lookoutmetrics',
    'machinelearning',
    'macie',
    'macie2',
    'managedblockchain',
    'marketplacecatalog',
    'marketplacecommerceanalytics',
    'marketplaceentitlement',
    'marketplaceentitlementservice',
    'marketplacemetering',
    'mediaconnect',
    'mediaconvert',
    'medialive',
    'mediapackage',
    'mediapackagevod',
    'mediastore',
    'mediastoredata',
    'mediatailor',
    'memorydb',
    'mgn',
    'migrationhub',
    'migrationhubconfig',
    'mobile',
    'mobileanalytics',
    'mq',
    'mturk',
    'mwaa',
    'neptune',
    'networkfirewall',
    'networkmanager',
    'nimblestudio',
    'opsworks',
    'opsworkscm',
    'organizations',
    'outposts',
    'personalize',
    'personalizeevents',
    'personalizeruntime',
    'pi',
    'pinpoint',
    'pinpointemail',
    'pinpointsmsvoice',
    'polly',
    'pricing',
    'prometheus',
    'prometheusservice',
    'proton',
    'qldb',
    'qldbsession',
    'quicksight',
    'ram',
    'rds',
    'rdsdata',
    'rdsdataservice',
    'redshift',
    'redshiftdata',
    'rekognition',
    'resourcegroups',
    'resourcegroupstagging',
    'resourcegroupstaggingapi',
    'robomaker',
    'route53',
    'route53domains',
    'route53recoverycontrolconfig',
    'route53recoveryreadiness',
    'route53resolver',
    's3',
    's3control',
    's3outposts',
    'sagemaker',
    'sagemakeredgemanager',
    'sagemakerfeaturestoreruntime',
    'sagemakerruntime',
    'savingsplans',
    'schemas',
    'sdb',
    'secretsmanager',
    'securityhub',
    'serverlessapplicationrepository',
    'serverlessapprepo',
    'serverlessrepo',
    'servicecatalog',
    'servicediscovery',
    'servicequotas',
    'ses',
    'sesv2',
    'sfn',
    'shield',
    'signer',
    'simpledb',
    'sms',
    'snowball',
    'sns',
    'sqs',
    'ssm',
    'ssmcontacts',
    'ssmincidents',
    'sso',
    'ssoadmin',
    'ssooidc',
    'stepfunctions',
    'storagegateway',
    'sts',
    'support',
    'swf',
    'synthetics',
    'textract',
    'timestreamquery',
    'timestreamwrite',
    'transcribe',
    'transcribeservice',
    'transcribestreaming',
    'transcribestreamingservice',
    'transfer',
    'translate',
    'waf',
    'wafregional',
    'wafv2',
    'wellarchitected',
    'workdocs',
    'worklink',
    'workmail',
    'workmailmessageflow',
    'workspaces',
    'xray',
]


def get_service_endpoint():
    protocol = 'https' if USE_SSL else 'http'
    endpoint = '%s://%s:%s' % (protocol, LOCALSTACK_HOSTNAME, EDGE_PORT)
    return endpoint


def prepare_config_file():
    file_name = 'Pulumi.%s.yaml' % PULUMI_STACK_NAME
    if os.path.exists(file_name):
        return file_name

    # construct endpoints config
    endpoint = get_service_endpoint()
    endpoints = DEFAULT_CONFIG['config']['aws:endpoints']
    if not endpoints:
        entry = {service: endpoint for service in SERVICES}
        endpoints.append(entry)

    # write local config file
    with open(file_name, 'w') as fp:
        fp.write(yaml.dump(DEFAULT_CONFIG))
    return file_name


def prepare_cmd_args():
    """
    Constructs command line arguments and hands over execution to the "pulumi" CLI
    """
    cmd_args = list(sys.argv)
    if 'up' in cmd_args and '-s' not in cmd_args:
        cmd_args += ['-s', PULUMI_STACK_NAME]
    return cmd_args


def main():
    prepare_config_file()

    if sys.argv[1] == 'init':
        # TODO: proper CLI using click/argparse
        cmd_args = [sys.argv[0], 'stack', 'init', PULUMI_STACK_NAME]
    else:
        cmd_args = prepare_cmd_args()

    return os.execvp(PULUMI_CMD, cmd_args)


if __name__ == '__main__':
    main()
