from __future__ import absolute_import, division, print_function, unicode_literals

import argparse
import boto3
import functools
import jsonschema
import logging
from ruamel import yaml

from c7n_mailer import deploy, utils
from c7n_mailer.sqs_queue_processor import MailerSqsQueueProcessor

CONFIG_SCHEMA = {
    'type': 'object',
    'additionalProperties': False,
    'required': ['queue_url', 'role', 'from_address'],
    'properties': {
        'queue_url': {'type': 'string'},
        'from_address': {'type': 'string'},
        'contact_tags': {'type': 'array', 'items': {'type': 'string'}},

        # Standard Lambda Function Config
        'region': {'type': 'string'},
        'role': {'type': 'string'},
        'runtime': {'type': 'string'},
        'memory': {'type': 'integer'},
        'timeout': {'type': 'integer'},
        'subnets': {'type': 'array', 'items': {'type': 'string'}},
        'security_groups': {'type': 'array', 'items': {'type': 'string'}},
        'dead_letter_config': {'type': 'object'},

        # Mailer Infrastructure Config
        'cache_engine': {'type': 'string'},
        'smtp_server': {'type': 'string'},
        'smtp_port': {'type': 'integer'},
        'smtp_ssl': {'type': 'boolean'},
        'smtp_username': {'type': 'string'},
        'smtp_password': {'type': 'string'},
        'ldap_email_key': {'type': 'string'},
        'ldap_uid_tags': {'type': 'array', 'items': {'type': 'string'}},
        'debug': {'type': 'boolean'},
        'ldap_uid_regex': {'type': 'string'},
        'ldap_uri': {'type': 'string'},
        'ldap_bind_dn': {'type': 'string'},
        'ldap_bind_user': {'type': 'string'},
        'ldap_uid_attribute': {'type': 'string'},
        'ldap_manager_attribute': {'type': 'string'},
        'ldap_email_attribute': {'type': 'string'},
        'ldap_bind_password_in_kms': {'type': 'boolean'},
        'ldap_bind_password': {'type': 'string'},
        'cross_accounts': {'type': 'object'},
        'ses_region': {'type': 'string'},
        'redis_host': {'type': 'string'},
        'redis_port': {'type': 'integer'},

        # SDK Config
        'profile': {'type': 'string'},
        'http_proxy': {'type': 'string'},
        'https_proxy': {'type': 'string'}
    }
}


def session_factory(mailer_config):
    return boto3.Session(
        region_name=mailer_config['region'],
        profile_name=mailer_config.get('profile', None))


def get_logger(debug=False):
    log_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    logging.basicConfig(level=logging.INFO, format=log_format)
    logging.getLogger('botocore').setLevel(logging.WARNING)
    if debug:
        logging.getLogger('botocore').setLevel(logging.DEBUG)
        debug_logger = logging.getLogger('custodian-mailer')
        debug_logger.setLevel(logging.DEBUG)
        return debug_logger
    else:
        return logging.getLogger('custodian-mailer')


def get_and_validate_mailer_config(args):
    with open(args.config) as fh:
        config = yaml.load(fh.read(), Loader=yaml.SafeLoader)
    jsonschema.validate(config, CONFIG_SCHEMA)
    utils.setup_defaults(config)
    return config


def get_c7n_mailer_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--config', required=True, help='mailer.yml config file')
    debug_help_msg = 'sets c7n_mailer logger to debug, for maximum output (the default is INFO)'
    parser.add_argument('--debug', action='store_true', help=debug_help_msg)
    max_num_processes_help_msg = 'will run the mailer in parallel, integer of max processes allowed'
    parser.add_argument('--max-num-processes', help=max_num_processes_help_msg)
    group = parser.add_mutually_exclusive_group(required=True)
    update_lambda_help_msg = 'packages your c7n_mailer, uploads the zip to aws lambda as a function'
    group.add_argument('--update-lambda', action='store_true', help=update_lambda_help_msg)
    run_help_msg = 'run c7n-mailer locally, process sqs messages and send emails or sns messages'
    group.add_argument('--run', action='store_true', help=run_help_msg)
    return parser


def run_mailer_in_parallel(mailer_config, aws_session, logger, max_num_processes):
    try:
        max_num_processes = int(max_num_processes)
        if max_num_processes < 1:
            raise Exception
    except:
        print('--max-num-processes must be an integer')
        return
    sqs_queue_processor = MailerSqsQueueProcessor(mailer_config, aws_session, logger)
    sqs_queue_processor.max_num_processes = max_num_processes
    sqs_queue_processor.run(parallel=True)


def main():
    parser = get_c7n_mailer_parser()
    args = parser.parse_args()
    mailer_config = get_and_validate_mailer_config(args)
    aws_session = session_factory(mailer_config)
    args_dict = vars(args)
    logger = get_logger(debug=args_dict.get('debug', False))
    if args_dict.get('update_lambda'):
        if args_dict.get('debug'):
            print('\n** --debug is only supported with --run, not --update-lambda **\n')
            return
        if args_dict.get('max_num_processes'):
            print('\n** --max-num-processes is only supported with --run, not --update-lambda **\n')
            return
        deploy.provision(mailer_config, functools.partial(session_factory, mailer_config))
    if args_dict.get('run'):
        max_num_processes = args_dict.get('max_num_processes')
        if max_num_processes:
            run_mailer_in_parallel(mailer_config, aws_session, logger, max_num_processes)
        else:
            MailerSqsQueueProcessor(mailer_config, aws_session, logger).run()


if __name__ == '__main__':
    main()
