#!/usr/bin/env python

""" standard """
import base64
import json
import operator
import os
import sys
import traceback
import urllib3
# disable ssl warning message
urllib3.disable_warnings()
""" third-party """
""" custom """
from tcex import TcEx

tcex = TcEx()

# supported action: clear, stage, validate
tcex.parser.add_argument('--action', help='The action to perform.', required=True)
tcex.parser.add_argument(
    '--data_file', help='The file containing the data to stage.', required=True)

args = tcex.args


def data_endswith(db_data, user_data):
    """Validate data ends with user data"""
    if db_data.endswith(user_data):
        return True
    return False


def data_in(db_data, user_data):
    """Validate data in user data"""
    if db_data in user_data:
        return True
    return False


def data_it(db_data, user_type):
    """Validate data is Type"""
    data_type = {
        'array': list,
        'binary': bytes,
        'bytes': bytes,
        'dict': dict,
        'entity': dict,
        'list': list,
        'str': str,
        'string': str
    }
    # user_type_tuple = tuple([data_type[t] for t in user_types])
    # if isinstance(db_data, user_type_tuple):
    if user_type is None:
        if db_data is None:
            return True
    elif user_type.lower() in ['null', 'none']:
        if db_data is None:
            return True
    elif data_type.get(user_type.lower()) is not None:
        if isinstance(db_data, data_type.get(user_type.lower())):
            return True
    return False


def data_not_in(db_data, user_data):
    """Validate data not in user data"""
    if db_data not in user_data:
        return True
    return False


def data_startswith(db_data, user_data):
    """Validate data starts with user data"""
    if db_data.startswith(user_data):
        return True
    return False


def main():
    """Main Logic"""
    # Define common comparison operators
    operators = {
        'eq': operator.eq,
        'ew': data_endswith,
        'ge': operator.ge,
        'gt': operator.gt,
        'in': data_in,
        'ni': data_not_in,
        'it': data_it,  # is type
        'lt': operator.lt,
        'le': operator.le,
        'ne': operator.ne,
        'sw': data_startswith
    }

    data_file = os.path.abspath(args.data_file)
    if os.path.isfile(data_file):  # double check file exist
        f = open(data_file, 'r')
        data_array = json.load(f)
        f.close()

        for ddata in data_array:
            variable = ddata.get('variable')
            user_data = ddata.get('data')
            if isinstance(user_data, int):
                user_data = str(ddata.get('data'))
            user_operator = ddata.get('operator', 'eq')

            if args.action == 'clear':
                tcex.playbook.delete(variable)
            elif args.action == 'validate':
                tcex.log.info(u'Validating output variable {}'.format(variable))
                # read from store
                db_data = tcex.playbook.read(variable)
                if variable.endswith('Binary') or variable.endswith('BinaryArray'):
                    tcex.log.debug('-> DB Data: ({}), Type: [{}]'.format(
                        'Excluding Binary Data Output', type(db_data)))
                else:
                    tcex.log.debug('-> DB Data: ({}), Type: [{}]'.format(db_data, type(db_data)))
                tcex.log.debug(u'- Operator: ({}) -'.format(user_operator))
                tcex.log.debug(
                    u'<- Validation Data: ({}), Type: [{}]'.format(user_data, type(user_data)))

                if user_operator in operators and operators.get(user_operator)(db_data, user_data):
                    tcex.log.info(u'Validation was successful')
                else:
                    tcex.log.error(u'Validation failed for variable: {}'.format(variable))
                    sys.exit(1)
            elif args.action == 'stage':
                if variable.endswith('Binary'):
                    user_data = base64.b64decode(user_data)
                tcex.log.info(u'Creating variable {}'.format(variable))
                tcex.playbook.create(variable, user_data)
            else:
                tcex.log.info(u'Invalid action provided: {}'.format(args.action))
                sys.exit(1)
    else:
        tcex.log.error(u'Could not open data file ({}).'.format(data_file))

    sys.exit(0)


if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        # TODO: Update this, possibly raise
        tcex.log.error(u'Generic Failure ({}).'.format(traceback.format_exc()))
        sys.exit(1)
