from django.core.urlresolvers import resolve, reverse
import furl
from rest_framework import serializers as ser
import pytz

from modularodm import Q

from framework.auth.core import Auth, User
from website import settings

from website.files.models import FileNode
from website.project.model import Comment
from website.util import api_v2_url

from api.base.serializers import (
    FileCommentRelationshipField,
    format_relationship_links,
    IDField,
    JSONAPIListField,
    JSONAPISerializer,
    Link,
    LinksField,
    NodeFileHyperLinkField,
    RelationshipField,
    TypeField,
    WaterbutlerLink,
)
from api.base.exceptions import Conflict
from api.base.utils import absolute_reverse
from api.base.utils import get_user_auth


class CheckoutField(ser.HyperlinkedRelatedField):

    default_error_messages = {'invalid_data': 'Checkout must be either the current user or null'}
    json_api_link = True  # serializes to a links object

    def __init__(self, **kwargs):
        kwargs['queryset'] = True
        kwargs['read_only'] = False
        kwargs['allow_null'] = True
        kwargs['lookup_field'] = 'pk'
        kwargs['lookup_url_kwarg'] = 'user_id'

        self.meta = {'id': 'user_id'}
        self.link_type = 'related'
        self.always_embed = kwargs.pop('always_embed', False)

        super(CheckoutField, self).__init__('users:user-detail', **kwargs)

    def resolve(self, resource):
        """
        Resolves the view when embedding.
        """
        embed_value = resource.stored_object.checkout.pk
        kwargs = {self.lookup_url_kwarg: embed_value}
        return resolve(
            reverse(
                self.view_name,
                kwargs=kwargs
            )
        )

    def get_queryset(self):
        return User.find(Q('_id', 'eq', self.context['request'].user._id))

    def get_url(self, obj, view_name, request, format):
        if obj is None:
            return {}
        return super(CheckoutField, self).get_url(obj, view_name, request, format)

    def to_internal_value(self, data):
        if data is None:
            return None
        try:
            return next(
                user for user in
                self.get_queryset()
                if user._id == data
            )
        except StopIteration:
            self.fail('invalid_data')

    def to_representation(self, value):

        url = super(CheckoutField, self).to_representation(value)

        rel_meta = None
        if value:
            rel_meta = {'id': value._id}

        ret = format_relationship_links(related_link=url, rel_meta=rel_meta)
        return ret


class FileTagField(ser.Field):
    def to_representation(self, obj):
        if obj is not None:
            return obj._id
        return None

    def to_internal_value(self, data):
        return data


class FileSerializer(JSONAPISerializer):
    filterable_fields = frozenset([
        'id',
        'name',
        'node',
        'kind',
        'path',
        'materialized_path',
        'size',
        'provider',
        'last_touched',
        'tags',
    ])
    id = IDField(source='_id', read_only=True)
    type = TypeField()
    guid = ser.SerializerMethodField(read_only=True,
                                     method_name='get_file_guid',
                                     help_text='OSF GUID for this file (if one has been assigned)')
    checkout = CheckoutField()
    name = ser.CharField(read_only=True, help_text='Display name used in the general user interface')
    kind = ser.CharField(read_only=True, help_text='Either folder or file')
    path = ser.CharField(read_only=True, help_text='The unique path used to reference this object')
    size = ser.SerializerMethodField(read_only=True, help_text='The size of this file at this version')
    provider = ser.CharField(read_only=True, help_text='The Add-on service this file originates from')
    materialized_path = ser.CharField(
        read_only=True, help_text='The Unix-style path of this object relative to the provider root')
    last_touched = ser.DateTimeField(read_only=True, help_text='The last time this file had information fetched about it via the OSF')
    date_modified = ser.SerializerMethodField(read_only=True, help_text='Timestamp when the file was last modified')
    date_created = ser.SerializerMethodField(read_only=True, help_text='Timestamp when the file was created')
    extra = ser.SerializerMethodField(read_only=True, help_text='Additional metadata about this file')
    tags = JSONAPIListField(child=FileTagField(), required=False)
    current_user_can_comment = ser.SerializerMethodField(help_text='Whether the current user is allowed to post comments')

    files = NodeFileHyperLinkField(
        related_view='nodes:node-files',
        related_view_kwargs={'node_id': '<node_id>', 'path': '<path>', 'provider': '<provider>'},
        kind='folder'
    )
    versions = NodeFileHyperLinkField(
        related_view='files:file-versions',
        related_view_kwargs={'file_id': '<_id>'},
        kind='file'
    )
    comments = FileCommentRelationshipField(related_view='nodes:node-comments',
                                            related_view_kwargs={'node_id': '<node._id>'},
                                            related_meta={'unread': 'get_unread_comments_count'},
                                            filter={'target': 'get_file_guid'}
                                            )
    node = RelationshipField(related_view='nodes:node-detail',
                             related_view_kwargs={'node_id': '<node._id>'},
                             help_text='The project that this file belongs to'
                             )
    links = LinksField({
        'info': Link('files:file-detail', kwargs={'file_id': '<_id>'}),
        'move': WaterbutlerLink(),
        'upload': WaterbutlerLink(),
        'delete': WaterbutlerLink(),
        'download': WaterbutlerLink(must_be_file=True),
        'new_folder': WaterbutlerLink(must_be_folder=True, kind='folder'),
    })

    class Meta:
        type_ = 'files'