# Copyright (c) 2014 Rackspace, Inc.
#
# 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.

from poppy.transport.validators.stoplight import decorators
from poppy.transport.validators.stoplight import exceptions
from poppy.transport.validators.stoplight import rule

from test_service_validation import BaseTestCase
# TODO(tonytan4ever): We probably want to move this to a
# test helpers library


@decorators.validation_function
def is_upper(z):
    """Simple validation function for testing purposes
    that ensures that input is all caps
    """
    if z.upper() != z:
        raise exceptions.ValidationFailed('{0} no uppercase'.format(z))

error_count = 0


def abort(code):
    global error_count
    error_count = error_count + 1

other_vals = dict()
get_other_val = other_vals.get


class DummyRequest(object):

    def __init__(self):
        self.headers = dict(header1='headervalue1')


class DummyResponse(object):
    pass


@decorators.validation_function
def is_request(candidate):
    if not isinstance(candidate, DummyRequest):
        raise exceptions.ValidationFailed('Input must be a request')


@decorators.validation_function
def is_response(candidate):
    if not isinstance(candidate, DummyResponse):
        raise exceptions.ValidationFailed('Input must be a response')


RequestRule = rule.Rule(is_request(), lambda error_info: abort(404))
ResponseRule = rule.Rule(is_response(), lambda error_info: abort(404))
UppercaseRule = rule.Rule(is_upper(), lambda error_info: abort(404))


class DummyEndpoint(object):

    # This should throw a ValidationProgrammingError
    # when called because the user did not actually
    # call validate_upper.

    # Note: the lambda in this function can never actually be
    # called, so we use no cover here

    @decorators.validate(
        value=rule.Rule(
            is_upper,
            lambda error_info: abort(404)))  # pragma: no cover
    def get_value_programming_error(self, value):
        # This function body should never be
        # callable since the validation error
        # should not allow it to be called
        assert False  # pragma: no cover

    @decorators.validate(
        value1=rule.Rule(is_upper(), lambda error_info: abort(404)),
        value2=rule.Rule(is_upper(), lambda error_info: abort(404)),
        value3=rule.Rule(is_upper(), lambda error_info: abort(404))
    )  # pragma: no cover
    def get_value_happy_path(self, value1, value2, value3):
        return value1 + value2 + value3

    @decorators.validate(
        value1=rule.Rule(is_upper(), lambda: abort(404)),
        value2=rule.Rule(is_upper(empty_ok=True),
                         lambda error_info: abort(404),
                         get_other_val),
    )  # pragma: no cover
    def get_value_with_getter(self, value1):
        global other_vals
        return value1 + other_vals.get('value2')

    # Falcon-style endpoint
    @decorators.validate(
        request=rule.Rule(is_request(), lambda error_info: abort(404)),
        response=rule.Rule(is_response(), lambda error_info: abort(404)),
        value=rule.Rule(is_upper(), lambda error_info: abort(404))
    )
    def get_falcon_style(self, request, response, value):
        return value

    # Falcon-style w/ declared rules
    @decorators.validate(request=RequestRule, response=ResponseRule,
                         value=UppercaseRule)
    def get_falcon_with_declared_rules(self, request, response, value):
        return value


class TestValidationFunction(BaseTestCase):

    def test_empty_ok(self):
        is_upper(empty_ok=True)('')

        with self.assertRaises(exceptions.ValidationFailed):
            is_upper()('')