# -*- coding: utf-8 -*-
import pytest

from flask import Flask, url_for
from werkzeug.routing import BuildError
from werkzeug.wrappers import BaseResponse
from flask_marshmallow import Marshmallow
from flask_marshmallow.fields import _tpl

from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow.sqla import HyperlinkRelated

import marshmallow

MARSHMALLOW_2 = int(marshmallow.__version__.split('.')[0]) >= 2

_app = Flask(__name__)

@_app.route('/author/<int:id>')
def author(id):
    return 'Steven Pressfield'

@_app.route('/authors/')
def authors():
    return 'Steven Pressfield, Chuck Paluhniuk'

@_app.route('/books/')
def books():
    return 'Legend of Bagger Vance, Fight Club'

@_app.route('/books/<id>')
def book(id):
    return 'Legend of Bagger Vance'

mar = Marshmallow(_app)

@pytest.yield_fixture(scope='function')
def app():

    ctx = _app.test_request_context()
    ctx.push()

    yield _app

    ctx.pop()

@pytest.fixture(scope='function')
def ma(app):
    return Marshmallow(app)


class MockModel(dict):
    def __init__(self, *args, **kwargs):
        super(MockModel, self).__init__(*args, **kwargs)
        self.__dict__ = self

class Author(MockModel):
    pass

class Book(MockModel):
    pass

@pytest.fixture
def mockauthor():
    author = Author(id=123, name='Fred Douglass')
    return author

@pytest.fixture
def mockbook(mockauthor):
    book = Book(id=42, author=mockauthor, title='Legend of Bagger Vance')
    return book


@pytest.mark.parametrize('template', [
    '<id>',
    ' <id>',
    '<id> ',
    '< id>',
    '<id  >',
    '< id >',
])
def test_tpl(template):
    assert _tpl(template) == 'id'
    assert _tpl(template) == 'id'
    assert _tpl(template) == 'id'

def test_url_field(ma, mockauthor):
    field = ma.URLFor('author', id='<id>')
    result = field.serialize('url', mockauthor)
    assert result == url_for('author', id=mockauthor.id)

    mockauthor.id = 0
    result = field.serialize('url', mockauthor)
    assert result == url_for('author', id=0)

def test_url_field_with_invalid_attribute(ma, mockauthor):
    field = ma.URLFor('author', id='<not-an-attr>')
    with pytest.raises(AttributeError) as excinfo:
        field.serialize('url', mockauthor)
    expected_msg = '{0!r} is not a valid attribute of {1!r}'.format(
        'not-an-attr', mockauthor)
    assert expected_msg in str(excinfo)

def test_url_field_deserialization(ma):
    field = ma.URLFor('author', id='<not-an-attr>', allow_none=True)
    # noop
    assert field.deserialize('foo') == 'foo'
    assert field.deserialize(None) is None

def test_invalid_endpoint_raises_build_error(ma, mockauthor):
    field = ma.URLFor('badendpoint')