# -*- coding: utf-8 -*-
"""
This class override the tastypie's ModelResource class

 - remove the meta object
 - remove the encapsulated data inside a sub objects
 - disable the page: no limit on the query
 - remove the resource_uri field

"""

import textwrap
import pytz
import json

from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
from django.conf import settings
from django.http import HttpResponse
from django.utils.timezone import is_naive

from tastypie.exceptions import (UnsupportedFormat,
                                 ImmediateHttpResponse, NotFound)
from tastypie.http import HttpNotImplemented, HttpApplicationError

try:
    from tastypie.http import HttpNotFound
except ImportError:
    # tastypie <= 0.9.10
    class HttpNotFound(HttpResponse):
        status_code = 404

from tastypie.resources import ModelResource
from tastypie.serializers import Serializer
from tastypie.bundle import Bundle


def my_handler(obj):
    """
    handle Bundle tastypie obj (Bundle might be nested)
    handle datetime formatting
    """
    if isinstance(obj, Bundle):
        obj = obj.data
    if hasattr(obj, 'isoformat'):
        return MySerializer.format_datetime(obj)
    return obj


class MySerializer(Serializer):

    """
    always return UTC datetimes in ISO 8601
    """

    @classmethod
    def format_datetime(cls, date):
        if is_naive(date):
            date = pytz.timezone(settings.TIME_ZONE).localize(date)
        if not isinstance(date.tzinfo, pytz.UTC.__class__):
            date = date.astimezone(pytz.UTC)
        # XXX date set in the admin doesn't have microsecond, but the one set
        #     with 'default=now' has, for consistency never output microsecond
        return date.replace(microsecond=0).isoformat()

    def to_html(self, data, options=None):
        if isinstance(data, dict) and 'fields' in data:
            title = settings.TITLE_SCHEMA
        else:
            title = settings.TITLE_RESULT
        return textwrap.dedent("""
        <!DOCTYPE html>
        <html>
          <head>
            <style>
              body {
                font-family: Monaco,"DejaVu Sans Mono",
                             "Courier New",monospace;
              }
              div {
                margin: 5px;
                padding: 5px;
                border: 1px solid #444;
                border-radius: 5px;
                background-color: #eee;
              }
              h1 {
                font-size: 1.4rem;
              }
              .command:before {
                font-size: 1.4rem;
              }
              pre {
                white-space: pre-wrap;
              }
            </style>
            <title>%(title)s</title>
          </head>
          <body>
            <div>
              <h1 class="command">%(title)s</h1>
              <pre>%(data)s</pre>
            </div>
          </body>
        </html>
        """) % {
            'title': title,
            'data': json.dumps(data, indent=4, sort_keys=True,
                               default=my_handler)
        }

    def serialize(self, bundle, format='application/json', options={}):
        try:
            return super(MySerializer, self).serialize(bundle, format, options)
        except (ImproperlyConfigured, UnsupportedFormat):
            raise ImmediateHttpResponse(
                HttpNotImplemented(settings.HTTP_NOT_IMPLEMENTED_ERROR)
            )
        except ImmediateHttpResponse:
            raise
        except Exception:
            raise ImmediateHttpResponse(
                HttpApplicationError(settings.HTTP_APPLICATION_ERROR)
            )


class RawModelResource(ModelResource):

    def accept_languages(self, request):
        if not request:
            return ['en', ]

        if hasattr(request, 'accept_languages'):
            return request.accept_languages

        accept_languages = []
        for lang in request.META.get('HTTP_ACCEPT_LANGUAGE', '').split(','):
            lang = lang.strip().split(';')[0]
            accept_languages.append(lang)
            accept_languages.append(lang.split('-')[0])
        accept_languages.append('en')
        setattr(request, 'accept_languages', accept_languages)
        return accept_languages

    def add_content_language(self, request, lang):
        if not request:
            return
        if not hasattr(request, 'content_language'):
            setattr(request, 'content_language', [])
        request.content_language.append(lang)

    def create_response(self, request, data, **response_kwargs):
        """
        to set the Content-Language Header
        """
        response = super(RawModelResource, self).create_response(
            request, data, **response_kwargs)

        if hasattr(response, '__setitem__'):
            content_language = getattr(request, 'content_language', None)
            if content_language and len(set(content_language)) == 1:
                response['Content-Language'] = content_language[0]
            if hasattr(request, 'total_count'):
                response['X-Total-Count'] = getattr(request, 'total_count')
        return response

    def alter_list_data_to_serialize(self, request, data_dict):
        if data_dict['meta'].get('total_count'):
            setattr(request, 'total_count', data_dict['meta']['total_count'])
        return data_dict['objects']

    def build_schema(self):
        schema = super(RawModelResource, self).build_schema()
        for key in schema['fields']:
            if schema['fields'][key]['type'] == 'datetime':
                schema['fields'][key]['help_text'] = \
                    'UTC datetimes in ISO 8601'
            if key == 'id':
                schema['fields'][key]['help_text'] = 'Id of the elem'
                schema['fields'][key]['type'] = 'integer'
            if 'default' in schema['fields'][key]:
                del schema['fields'][key]['default']
        return schema

    def obj_get(self, **kwargs):
        try:
            return super(RawModelResource, self).obj_get(**kwargs)
        except (NotFound, ObjectDoesNotExist):
            raise ImmediateHttpResponse(
                HttpNotFound(settings.HTTP_NOT_FOUND)
            )
        except ImmediateHttpResponse:
            raise
        except Exception:
            raise ImmediateHttpResponse(
                HttpApplicationError(settings.HTTP_APPLICATION_ERROR)
            )

    def obj_get_list(self, **kwargs):
        try:
            return super(RawModelResource, self).obj_get_list(**kwargs)
        except (NotFound, ObjectDoesNotExist):
            raise ImmediateHttpResponse(
                HttpNotFound(settings.HTTP_NOT_FOUND)
            )
        except ImmediateHttpResponse:
            raise
        except Exception:
            raise ImmediateHttpResponse(
                HttpApplicationError(settings.HTTP_APPLICATION_ERROR)
            )

    class Meta:
        max_limit = None
        include_resource_uri = False
        allowed_methods = ['get']
        serializer = MySerializer()