import collections
import http
import json
import uuid
from unittest import mock

import marshmallow_jsonapi
from marshmallow_jsonapi import fields

from flask_jsonapi import api
from flask_jsonapi import resource_repositories

JSONAPI_HEADERS = {'content-type': 'application/vnd.api+json', 'accept': 'application/vnd.api+json'}


class ChildSchema(marshmallow_jsonapi.Schema):
    id = fields.UUID(required=True)
    name = fields.Str()

    class Meta:
        type_ = 'childs'
        strict = True


class ParentSchema(marshmallow_jsonapi.Schema):
    id = fields.UUID(required=True)
    name = fields.Str()
    children = fields.Relationship(schema=ChildSchema, type_='childs', many=True)

    class Meta:
        type_ = 'parents'
        include_resource_linkage = True
        strict = True


ParentModel = collections.namedtuple('ParentModel', 'id name children')
ChildModel = collections.namedtuple('ChildModel', 'id name')


class ParentDetailRepository:
    def get_detail(self, id):
        return ParentModel(
            id=id, name='Adam',
            children=[
                ChildModel(id=uuid.uuid4(), name='Cain'),
                ChildModel(id=uuid.uuid4(), name='Abel'),
            ]
        )


class ParentResourceRepositoryViewSet(resource_repositories.ResourceRepositoryViewSet):
    schema = ParentSchema
    repository = ParentDetailRepository()


def test_get_parent_detail_with_include_data(app):
    application_api = api.Api(app)
    application_api.repository(ParentResourceRepositoryViewSet(), 'parent', '/parents/')
    response = app.test_client().get(
        '/parents/f60717a3-7dc2-4f1a-bdf4-f2804c3127a4/?include=children',
        headers=JSONAPI_HEADERS
    )
    result = json.loads(response.data.decode())
    expected = {
       'data': {
          'attributes': {
             'name': 'Adam'
          },
          'id': 'f60717a3-7dc2-4f1a-bdf4-f2804c3127a4',
          'relationships': {
             'children': {
                'data': [
                   {
                      'id': mock.ANY,
                      'type': 'childs'
                   },
                   {
                      'id': mock.ANY,
                      'type': 'childs'
                   }
                ]
             }
          },
          'type': 'parents'
       },
       'included': [
          {
             'attributes': {
                'name': 'Cain'
             },
             'id': mock.ANY,
             'type': 'childs'
          },
          {
             'attributes': {
                'name': 'Abel'
             },
             'id': mock.ANY,
             'type': 'childs'
          }
       ],
       'jsonapi': {
          'version': '1.0'
       }
    }
    assert expected == result


def test_get_parent_detail_without_include_data(app):
    application_api = api.Api(app)
    application_api.repository(ParentResourceRepositoryViewSet(), 'parent', '/parents/')
    response = app.test_client().get(
        '/parents/f60717a3-7dc2-4f1a-bdf4-f2804c3127a4/',
        headers=JSONAPI_HEADERS
    )
    result = json.loads(response.data.decode())
    expected = {
        'data': {
            'type': 'parents',
            'id': 'f60717a3-7dc2-4f1a-bdf4-f2804c3127a4',
            'attributes': {
                'name': 'Adam'
            }
        },
        'jsonapi': {
            'version': '1.0'
        }
    }
    assert expected == result


def test_invalid_include_parameter_response(app):
    application_api = api.Api(app)
    application_api.repository(ParentResourceRepositoryViewSet(), 'parent', '/parents/')
    response = app.test_client().get(
        '/parents/f60717a3-7dc2-4f1a-bdf4-f2804c3127a4/?include=children.children',
        headers=JSONAPI_HEADERS
    )
    assert response.status_code == http.HTTPStatus.BAD_REQUEST

@@ -1735,33 +1735,107 @@
 nse.data.decode(
-)
+'utf-8'))%0A    result%5B'included'%5D.sort(key=lambda x: x%5B'attributes'%5D%5B'name'%5D
 )%0A    expected =
@@ -2405,34 +2405,37 @@
 d': %5B%0A          
+ 
 %7B%0A
+  
              'at
@@ -2455,32 +2455,35 @@
                 
+   
 'name': 'Cain'%0A 
@@ -2479,14 +2479,16 @@
 ': '
-Cain'%0A
+Abel'%0A  
     
@@ -2504,32 +2504,34 @@
 %7D,%0A             
+ 
+ 
 'id': mock.ANY,%0A
@@ -2522,32 +2522,34 @@
 'id': mock.ANY,%0A
+  
              'ty
@@ -2564,35 +2564,37 @@
 ilds'%0A          
+ 
 %7D,%0A
+ 
           %7B%0A    
@@ -2594,32 +2594,34 @@
  %7B%0A             
+  
 'attributes': %7B%0A
@@ -2628,32 +2628,35 @@
                 
+   
 'name': 'Abel'%0A 
@@ -2640,38 +2640,40 @@
        'name': '
-Abel'%0A
+Cain'%0A  
              %7D,%0A
@@ -2677,32 +2677,34 @@
 %7D,%0A             
+ 
+ 
 'id': mock.ANY,%0A
@@ -2695,32 +2695,34 @@
 'id': mock.ANY,%0A
+  
              'ty
@@ -2737,33 +2737,35 @@
 ilds'%0A          
-%7D
+ %7D,
 %0A       %5D,%0A     

Fix order in test.