import logging
import pytest
import json

from django.test.client import RequestFactory
from django.http import Http404
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied


from passerelle.utils import to_json

class WrappedException(Exception):
    pass


class LogAsWarningException(Exception):
    err_code = 'logaswarningexception'
    http_status = 488
    log_error = False

    def __str__(sefl):
        return 'log as warning exception'


@to_json('api')
def wrapped_exception(req, *args, **kwargs):
    raise WrappedException


@to_json('api')
def log_as_warning_exception(req, *args, **kwargs):
    raise LogAsWarningException


@to_json('api')
def http404_exception(req, *args, **kwargs):
    raise Http404

@to_json('api')
def doesnotexist_exception(req, *args, **kwargs):
    raise ObjectDoesNotExist


@to_json('api')
def permissiondenied_exception(req, *args, **kwargs):
    raise PermissionDenied


def test_jsonresponselog_get(caplog):
    request = RequestFactory()
    wrapped_exception(request.get('/'))
    post_payload = {'data': 'plop'}
    with pytest.raises(WrappedException):
        wrapped_exception(request.post('/?raise=1', post_payload))

    for record in caplog.records():
        assert record.name == 'passerelle.jsonresponse'
        assert record.levelno == logging.ERROR
        assert hasattr(record, 'method')
        if record.method == 'POST':
            assert hasattr(record, 'body')
        assert "Error occurred while processing request" in record.message

def test_jsonresponselog_http404(caplog):
    request = RequestFactory()
    http404_exception(request.get('/'))
    assert caplog.records() == []

def test_jsonresponselog_doesnotexist(caplog):
    request = RequestFactory()
    doesnotexist_exception(request.get('/'))
    for record in caplog.records():
        assert record.name == 'passerelle.jsonresponse'
        assert record.levelno == logging.WARNING
        assert 'object not found' in record.message


def test_jsonresponselog_permissiondenied(caplog):
    request = RequestFactory()
    permissiondenied_exception(request.get('/'))
    for record in caplog.records():
        assert record.name == 'passerelle.jsonresponse'
        assert record.levelno == logging.WARNING
        assert 'Permission denied' in record.message


def test_jsonresponse_log_as_warning_exception(caplog):
    request = RequestFactory()
    response = log_as_warning_exception(request.get('/'))
    records = caplog.records()
    assert len(records) == 1
    record = records[0]
    assert record.name == 'passerelle.jsonresponse'
    assert record.levelno == logging.WARNING
    assert hasattr(record, 'method')
    assert record.method == 'GET'
    assert "Error occurred while processing request" in record.message
    assert response.status_code == 488
    data = json.loads(response.content)
    assert data['err'] == 'logaswarningexception'
    assert data['err_desc'] == 'log as warning exception'


def test_jsonresponse_error_header():
    request = RequestFactory()
    req = request.get('/')
    @to_json('api')
    def test_func(req):
        return {"test": "un test"}

    result = test_func(req)
    assert result.has_header('x-error-code')
    assert result['x-error-code'] == '0'
    assert result.status_code == 200
    data = json.loads(result.content)
    assert 'err' in data
    assert data['err'] == 0
    assert 'data' in data
    assert 'test' in data['data']
    assert data['data']['test'] == 'un test'
    @to_json('api')
    def test_func(req):
        class CustomException(Exception):
            http_status = 200
        raise CustomException

    result = test_func(req)
    data = json.loads(result.content)
    assert 'err_class' in data
    assert 'err' in data
    assert data['err'] == 1
    assert data['err_class'] == 'test_jsonresponse.CustomException'
    assert result.status_code == 200
    assert result.has_header('x-error-code')
    assert result['x-error-code'] == '1'

def test_jsonresponse_without_wrapping():
    request = RequestFactory()
    req = request.get('/')
    @to_json('api', wrap_response=False)
    def test_func(req):
        return {"foo": "bar"}
    result = test_func(req)
    data = json.loads(result.content)
    assert data == {"foo": "bar"}

def test_jsonresponse_with_callback():
    request = RequestFactory()
    req = request.get('/?callback=myfunc')
    @to_json('api')
    def test_func(req):
        return {"foo": "bar"}
    result = test_func(req)
    content_type = result.get('Content-Type')
    assert 'application/javascript' in content_type
    assert result.content.startswith('myfunc(')
    args = json.loads(result.content[7:-2])
    assert args['err'] == 0
    assert args['data'] == {"foo": "bar"}

def test_jsonresponse_with_wrong_callback():
    request = RequestFactory()
    req = request.get('/?callback=myfunc()')
    @to_json('api')
    def test_func(req):
        return {"foo": "bar"}
    result = test_func(req)
    assert result.status_code == 400
