from flask import jsonify, request, Flask, make_response
import logging
import re

mock_server = Flask(__name__)
_rules = []

@mock_server.route("/mock/shutdown", methods=['GET'])
def shutdown():
    func = request.environ.get('werkzeug.server.shutdown')
    if func is None:
        raise RuntimeError('Not running with the Werkzeug Server')
    func()
    return 'Server shutting down...'


@mock_server.route("/mock/responses", methods=['POST'])
def add_response():
    """
    This method adds new responses to the mock.
    To add a response send a POST request with a payload like this:

    {
        "url_filter": ".*",
        "headers": {
            "Accept": "text/xml"
        },
        "body": "Sample body",
        "status_code": 200
    }

    Server will validate each matching rule and apply the first match
    If there is no match, it will return a 500 response
    """
    try:
        payload = request.get_json(force=True)
    except:
        logging.error("Payload is not a valid JSON string")
        logging.error(request.data)
        return "Payload is not valid JSON string", 400

    #Parse data from request
    if "url_filter" in payload.keys():
        try:
            url_filter = re.compile(payload["url_filter"])
        except Exception as e:
            logging.error("url_filter is not a valid regular expression")
            logging.error(payload["url_filter"])
            return "url_filter is not a valid regular expression:\\n%s" % e.message, 400
    else:
        url_filter = re.compile('.*')

    if "headers" in payload.keys():
        if type(payload["headers"]) is dict:
            headers = payload["headers"]
        else:
            return "headers is not a dictionary:\\n%s" % payload["headers"], 400
    else:
        headers = {}

    if "body" in payload.keys():
        body = payload["body"]
    else:
        body = ""

    if "status_code" in payload.keys():
        status_code = payload["status_code"]
    else:
        status_code = 200

    #Save parsed data
    rule = {"url_filter": url_filter, "headers": headers, "body": body, "status_code": status_code}
    _rules.append(rule)

    return "OK"


@mock_server.route("/mock/responses", methods=['DELETE'])
def clear_responses():
    """
    Delete existing responses
    """
    del _rules[0:len(_rules)]
    return "All rules were deleted"


@mock_server.route("/mock/responses", methods=['GET'])
def get_responses():
    """
    Get all responses
    """
    rules_as_text = []
    for rule in _rules:
        #make a copy so we don't modify original
        rule = rule.copy()

        #Convert regex to str
        rule["url_filter"] = rule["url_filter"].pattern

        #Add rule to list
        rules_as_text.append(rule)

    return jsonify(rules=rules_as_text)


@mock_server.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT', 'DELETE'])
@mock_server.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def catch_all(path):
    """
    This method will catch all requests for which there are no explicit routes.
    Here is where we build responses based on the rules that have been configured
    It will go though the list of rules and apply one by one until a match is found.
    If there is no match, it will return a 500 response
    """
    for rule in _rules:
        regex = rule["url_filter"]
        if regex.match(path):
            response = make_response()
            response .headers = rule["headers"]
            response .data = rule["body"]
            response .status_code = rule["status_code"]
            return response
            # return rule["body"], rule["status_code"]

    # Default values returned when there wasn't a match in the rules
    return "Mock has not been configured", 500


if __name__ == '__main__':
    mock_server.run(host='127.0.0.1', port=10000)
