#!/usr/bin/env python3
#
# Copyright 2020 Nicholas de Jong  <contact[at]nicholasdejong.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os
import ast
import json
import sys
import inspect
import argparse

try:
    import PfsenseFauxapi
except:
    sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
    import PfsenseFauxapi


class FauxAPIPyException(Exception):
    pass


class FauxAPIPy:

    name = 'FauxAPI'
    args = None
    argparse = None

    def __init__(self):
        self.argparse = argparse.ArgumentParser(description=self.name)

        group_call = self.argparse.add_argument_group('Call')
        group_call.add_argument('--host', type=str, metavar='[host]', required=False,
                            help='Host address of the target pfSense host with the PfsenseFauxapi package installed.')
        group_call.add_argument('--apikey', type=str, metavar='[key]', required=False,
                            help='FauxAPI apikey value - alternatively via the FAUXAPI_APIKEY environment variable.')
        group_call.add_argument('--apisecret', type=str, metavar='[secret]', required=False,
                            help='FauxAPI apisecret value - alternatively via the FAUXAPI_APISECRET environment variable.')
        group_call.add_argument('--verified-ssl', action='store_true', default=False,
                            help='Enable SSL certificate checks - default does NOT check SSL certificates.')
        group_call.add_argument('--debug', action='store_true', default=False,
                            help='Enable debug response from the remote FauxAPI - helpful in tracking down issues.')
        group_call.add_argument('function', metavar='[function]', type=str, nargs='+',
                            help='The FauxAPI function being called')
        group_call.add_argument('function_args', metavar='[function-args]', type=str, nargs='?',
                            help='Arguments to the function, space separated')

        self.args = self.argparse.parse_args()

    def main(self):

        if self.args.apikey:
            apikey = self.args.apikey
        elif os.getenv('FAUXAPI_APIKEY'):
            apikey = os.getenv('FAUXAPI_APIKEY')
        else:
            self.argparse.print_help(sys.stderr)
            sys.exit(1)

        if self.args.apisecret:
            apisecret = self.args.apisecret
        elif os.getenv('FAUXAPI_APISECRET'):
            apisecret = os.getenv('FAUXAPI_APISECRET')
        else:
            self.argparse.print_help(sys.stderr)
            sys.exit(1)

        # munge the function args
        if type(self.args.function_args) is list:
            self.args.function.extend(self.args.function_args)

        function = self.args.function[0]
        function_args = self.args.function[1:]

        fauxapi = PfsenseFauxapi.PfsenseFauxapi(
            host=self.args.host,
            apikey=apikey,
            apisecret=apisecret,
            use_verified_https=self.args.verified_ssl,
            debug=self.args.debug
        )

        if function not in dir(fauxapi):
            print()
            print('ERROR: Requested "{}" is not a known function'.format(function))
            print()
            print('Functions available:-')

            funcs = inspect.getmembers(fauxapi, predicate=inspect.ismethod)
            funcs.sort()

            for f, _ in funcs:
                if f[0] != '_':
                    print(' - {}'.format(f))
            print()
            sys.exit(1)

        try:
            if function_args is None or len(function_args) == 0:
                result = getattr(fauxapi, function)()
            elif function_args is None or len(function_args) == 1:
                result = getattr(fauxapi, function)(function_args[0])
            elif function_args is None or len(function_args) == 2:
                result = getattr(fauxapi, function)(function_args[0], function_args[1])
            elif function_args is None or len(function_args) == 3:
                result = getattr(fauxapi, function)(function_args[0], function_args[1], function_args[2])
            elif function_args is None or len(function_args) == 4:
                result = getattr(fauxapi, function)(function_args[0], function_args[1], function_args[2], function_args[3])
            else:
                result = {'error': 'Too many input args provided'}

        except PfsenseFauxapiException as e:

            try:
                error_string = str(e.args)
                if error_string[-3:] == "',)":
                    error_string = error_string[:-3] + "','')"
                error_message, error_data = ast.literal_eval(error_string)
                result = {
                    'error': error_message,
                    'data': error_data
                }
            except ValueError:
                result = {
                    'error': str(e.args),
                }

        print(json.dumps(result))


if __name__ == '__main__':
    FauxAPIPy().main()
