# -*- coding: utf-8 -*-
from django.core.exceptions import ImproperlyConfigured
from django.http import HttpResponse, HttpResponseForbidden
from django.test import TestCase, RequestFactory

from ..decorators import (
    _hmac,
    _match,
    verify_signature
)
from ..compat import mock

# taken from a real requestbin webhook callback
TEST_WEBHOOK_TOKEN = b'bLFiN4S09FV1nH5G7ZJc3nCYqeMZrHcU'
TEST_REQUEST_SIGNATURE = '32f77520f7b025f15ef3ab55be178667c92827e3'
# HttpRequest.body is a bytestring
TEST_REQUEST_BODY = (
    b'{"payload":{"resource_type":"check","action":"check.form_opened",'
    b'"object":{"id":"923d2717-9abd-4c0b-bc4f-33d769547df5",'
    b'"status":"awaiting_applicant","completed_at":"2016-10-26 16:18:24 UTC",'
    b'"href":"https://api.onfido.com/v1/applicants/4d2ff0dc-3352-4eed-9b7c-'
    b'86ac7b619e4e/checks/923d2717-9abd-4c0b-bc4f-33d769547df5"}}}'
)


class DecoratorTests(TestCase):

    """onfido.decorator module tests."""

    def setUp(self):
        self.factory = RequestFactory()

    def get_request(self, body=TEST_REQUEST_BODY, signature=TEST_REQUEST_SIGNATURE):
        """Create test request."""
        if signature:
            return self.factory.post(
                '/', body,
                content_type='application/json',
                HTTP_X_SIGNATURE=signature
            )
        else:
            return self.factory.post(
                '/', body,
                content_type='application/json'
            )

    def test__hmac(self):
        """Test the _hmac function."""
        self.assertEqual(
            _hmac(TEST_WEBHOOK_TOKEN, TEST_REQUEST_BODY),
            TEST_REQUEST_SIGNATURE
        )

    def test__match(self):
        """Test the _match function."""

        def match(token, body):
            request = self.get_request(body)
            return _match(token, request)

        self.assertTrue(match(TEST_WEBHOOK_TOKEN, TEST_REQUEST_BODY))
        self.assertFalse(match('foo', TEST_REQUEST_BODY))
        self.assertFalse(match(TEST_WEBHOOK_TOKEN, 'bar'))

        # test with a good request, but various HMAC error
        with mock.patch('onfido.decorators._hmac') as mock_hmac:
            mock_hmac.side_effect = KeyError()
            self.assertFalse(match(TEST_WEBHOOK_TOKEN, TEST_REQUEST_BODY))
            mock_hmac.side_effect = Exception("We are f-secure")
            self.assertFalse(match(TEST_WEBHOOK_TOKEN, TEST_REQUEST_BODY))

        # test bad request (missing the X-Signature header)
        request = self.get_request(signature=None)
        self.assertFalse(_match(TEST_WEBHOOK_TOKEN, request))

    @mock.patch('onfido.decorators._match')
    def test_verify_signature(self, mock_match):
        """Test the view function decorator itself."""

        @verify_signature()
        def request_function(request):
            """Fake view function that just returns a 200."""
            return HttpResponse()

        request = self.get_request()

        # import module as we want to manipulate the WEBHOOK_TOKEN
        from .. import decorators

        # in TEST_MODE we return immediately
        decorators.TEST_MODE = True
        decorators.WEBHOOK_TOKEN = None
        mock_match.reset_mock()
        request_function(request)
        mock_match.assert_not_called()

        # without a WEBHOOK_TOKEN we should get an error
        decorators.TEST_MODE = False
        decorators.WEBHOOK_TOKEN = None
        self.assertRaises(ImproperlyConfigured, request_function, request)
        mock_match.assert_not_called()

        # mock out _hmac so we can force a pass / fail
        decorators.TEST_MODE = False
        decorators.WEBHOOK_TOKEN = TEST_WEBHOOK_TOKEN
        mock_match.return_value = True
        self.assertIsInstance(request_function(request), HttpResponse)
        mock_match.return_value = False
        self.assertIsInstance(request_function(request), HttpResponseForbidden)
