# -*- coding: utf-8 -*-
u""" 1flow core API.

.. Copyright 2015 Olivier Cortès <oc@1flow.io>.

    This file is part of the 1flow project.

    1flow is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    1flow is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public
    License along with 1flow.  If not, see http://www.gnu.org/licenses/
"""

import logging
from oneflow.core import models

from rest_framework import viewsets, mixins, exceptions

from sparks.django.rest import (
    # IsOwnerOrAdmin,
    IsOwnerOrAdminReadOnly,
    IsOwnerOrAuthenticatedReadOnly,
    # IsAdminOrReadOnly,
    IsAdminOrAuthenticatedReadOnly,
)

from .serializers import (
    HelpContentSerializer,
    LanguageSerializer,
    WebSiteSerializer,
    AuthorSerializer,
    SimpleTagSerializer,
    FolderSerializer,

    ProcessorCategorySerializer,
    ProcessorSerializer,
    ChainedItemSerializer,
    ProcessingChainSerializer,

    BaseFeedSerializer,
    RssAtomFeedSerializer,
    MailAccountSerializer,
    MailFeedSerializer,
    TwitterAccountSerializer,
    TwitterFeedSerializer,
    SubscriptionSerializer,


    BaseItemSerializer,
    ArticleSerializer,
    TweetSerializer,
    # EmailSerializer,
    ReadSerializer,
)

LOGGER = logging.getLogger(__name__)


class ListRetrieveMixin(mixins.ListModelMixin, mixins.RetrieveModelMixin):

    """ Simple mix of list & retreive mixins. """

    pass


class HelpContentViewSet(viewsets.ModelViewSet):

    """ help content. """

    permission_classes = (IsAdminOrAuthenticatedReadOnly, )
    queryset = models.HelpContent.objects.all()
    serializer_class = HelpContentSerializer


class LanguageViewSet(viewsets.ModelViewSet):

    """ 1flow language. """

    permission_classes = (IsAdminOrAuthenticatedReadOnly, )
    queryset = models.Language.objects.all()
    serializer_class = LanguageSerializer


class FolderViewSet(viewsets.ModelViewSet):

    """ User folders.

    Only subscriptions are stored in folders.
    """

    permission_classes = (IsOwnerOrAdminReadOnly, )
    queryset = models.Folder.objects.all()
    serializer_class = FolderSerializer

    def get_queryset(self):
        """ Filter folders of current request user.

        .. todo:: use query filter if user is admin to get feeds of any user.
        """

        return self.queryset.filter(user_id=self.request.user.id)

    def update(self, request, pk=None):
        """ Update a folder, but disallow updates on the root folder. """

        if int(pk) == models.Folder.get_root_for(request.user).id:
            raise exceptions.PermissionDenied(u'user root folder is read-only')

        return super(FolderViewSet, self).update(request, pk)

    def partial_update(self, request, pk=None):
        """ [partial] Update a folder, but disallow updates on the root one. """

        if int(pk) == models.Folder.get_root_for(request.user).id:
            raise exceptions.PermissionDenied(u'user root folder is read-only')

        return super(FolderViewSet, self).partial_update(request, pk)


class WebSiteViewSet(viewsets.ModelViewSet):

    """ WebSite model. """

    permission_classes = (IsAdminOrAuthenticatedReadOnly, )
    queryset = models.WebSite.objects.all()
    serializer_class = WebSiteSerializer


class AuthorViewSet(viewsets.ModelViewSet):

    """ Author model. """

    permission_classes = (IsAdminOrAuthenticatedReadOnly, )
    queryset = models.Author.objects.all()
    serializer_class = AuthorSerializer


class SimpleTagViewSet(viewsets.ModelViewSet):

    """ SimpleTag model. """

    permission_classes = (IsAdminOrAuthenticatedReadOnly, )
    queryset = models.SimpleTag.objects.all()
    serializer_class = SimpleTagSerializer


# —————————————————————————————————————————————————————————————————— Processing


class ProcessorCategoryViewSet(viewsets.ModelViewSet):

    """ ProcessorCategory model. """

    permission_classes = (IsAdminOrAuthenticatedReadOnly, )
    queryset = models.ProcessorCategory.objects.all()
    serializer_class = ProcessorCategorySerializer


class ProcessorViewSet(viewsets.ModelViewSet):

    """ Processor model. """

    permission_classes = (IsAdminOrAuthenticatedReadOnly, )
    queryset = models.Processor.objects.all()
    serializer_class = ProcessorSerializer


class ChainedItemViewSet(viewsets.ModelViewSet):

    """ ChainedItem model. """

    permission_classes = (IsAdminOrAuthenticatedReadOnly, )
    queryset = models.ChainedItem.objects.all()
    serializer_class = ChainedItemSerializer


class ProcessingChainViewSet(viewsets.ModelViewSet):

    """ ProcessingChain model. """

    permission_classes = (IsAdminOrAuthenticatedReadOnly, )
    queryset = models.ProcessingChain.objects.all()
    serializer_class = ProcessingChainSerializer


# ———————————————————————————————————————————————————————————— Accounts & Feeds


class BaseFeedViewSet(ListRetrieveMixin, viewsets.GenericViewSet):

    u""" BaseFeed model **(read-only)**.

    This listing is used to obtain a consolidated list of all feeds,
    whatever their type (Atom/Mail/Twitter/…).

    To get specific feed details, you get them by ID in the dedicated API
    endpoints (`/api/twitter-feeds/`, etc).

    **warning:** I didn't find a way to create the absolute URL to specialized
        detail endpoint yet, you'll have to build it in the client, from the
        `type` attribute, adding the ending `s`… This is suboptimal, I know.
    """

    permission_classes = (IsOwnerOrAdminReadOnly, )
    queryset = models.BaseFeed.objects.all()
    serializer_class = BaseFeedSerializer


class UserFeedsViewSet(viewsets.ModelViewSet):

    """ User special feeds. """

    permission_classes = (IsOwnerOrAdminReadOnly, )
    queryset = models.BaseFeed.objects.all()
    serializer_class = BaseFeedSerializer

    def get_queryset(self):
        """ Filter own user_feeds of current request user.

        .. todo:: use query filter if user is admin to get feeds of any user.
        """

        return self.queryset.filter(id__in=self.request.user.user_feeds.all_ids)


class RssAtomFeedViewSet(viewsets.ModelViewSet):

    """ RSS/Atom feed model. """

    permission_classes = (IsAdminOrAuthenticatedReadOnly, )
    queryset = models.RssAtomFeed.objects.all()
    serializer_class = RssAtomFeedSerializer


class MailAccountViewSet(viewsets.ModelViewSet):

    """ Mail account model. """

    permission_classes = (IsOwnerOrAdminReadOnly, )
    queryset = models.MailAccount.objects.all()
    serializer_class = MailAccountSerializer

    def get_queryset(self):
        """ Filter accounts of current request user.

        .. todo:: use query filter if user is admin to get feeds of any user.
        """

        return self.queryset.filter(user_id=self.request.user.id)


class MailFeedViewSet(viewsets.ModelViewSet):

    """ Mail feed model. """

    permission_classes = (IsOwnerOrAdminReadOnly, )
    queryset = models.MailFeed.objects.all()
    serializer_class = MailFeedSerializer

    def get_queryset(self):
        """ Filter feeds of current request user or other's public feeds.

        .. todo:: implement other's public feeds. for now we get only
            the current user feeds.
        """

        return self.queryset.filter(user_id=self.request.user.id)


class TwitterAccountViewSet(viewsets.ModelViewSet):

    """ Mail account model. """

    permission_classes = (IsOwnerOrAdminReadOnly, )
    queryset = models.TwitterAccount.objects.all()
    serializer_class = TwitterAccountSerializer

    def get_queryset(self):
        """ Filter accounts of current request user.

        .. todo:: use query filter if user is admin to get feeds of any user.
        """

        return self.queryset.filter(user_id=self.request.user.id)


class TwitterFeedViewSet(viewsets.ModelViewSet):

    """ Twitter feed model. """

    permission_classes = (IsOwnerOrAuthenticatedReadOnly, )
    queryset = models.TwitterFeed.objects.all()
    serializer_class = TwitterFeedSerializer

    def get_queryset(self):
        """ Filter feeds of current request user or other's public feeds.

        .. todo:: implement other's public feeds. for now we get only
            the current user feeds.
        """

        return self.queryset.filter(user_id=self.request.user.id)


class UserSubscriptionsViewSet(viewsets.ModelViewSet):

    """ User special feeds. """

    permission_classes = (IsOwnerOrAdminReadOnly, )
    queryset = models.Subscription.objects.all()
    serializer_class = SubscriptionSerializer

    def get_queryset(self):
        """ Filter own user_subscriptions of current request user.

        .. todo:: use query filter if user is admin to get feeds of any user.
        """

        return self.queryset.filter(
            id__in=self.request.user.user_subscriptions.all_ids
        )


class SubscriptionViewSet(viewsets.ModelViewSet):

    """ User subscriptions to feeds. """

    permission_classes = (IsOwnerOrAdminReadOnly, )
    queryset = models.Subscription.objects.all()
    serializer_class = SubscriptionSerializer

    def get_queryset(self):
        """ Filter subscriptions of current request user.

        .. todo:: use query filter if user is admin to get feeds of any user.
        """

        return self.queryset.filter(user_id=self.request.user.id)


# ——————————————————————————————————————————————————————————————————————— Items


class BaseItemViewSet(ListRetrieveMixin, viewsets.GenericViewSet):

    u""" BaseItem model **(read-only)**.

    This listing is used to obtain a consolidated list of all items,
    whatever their type (Article/e-Mail/Tweet/…).

    To get specific item details, you get them by ID in the dedicated API
    endpoints (`/api/tweets/`, etc).

    **warning:** I didn't find a way to create the absolute URL to specialized
        detail endpoint yet, you'll have to build it in the client, from the
        `type` attribute, adding the ending `s`… This is suboptimal, I know.
    """

    permission_classes = (IsOwnerOrAuthenticatedReadOnly, )
    queryset = models.BaseItem.objects.all()
    serializer_class = BaseItemSerializer


class ArticleViewSet(viewsets.ModelViewSet):

    """ 1flow Article (=a web page / news article). """

    permission_classes = (IsOwnerOrAuthenticatedReadOnly, )
    queryset = models.Article.objects.all()
    serializer_class = ArticleSerializer


class TweetViewSet(viewsets.ModelViewSet):

    """ a Tweet. 140 characters of pure electronic joy. """

    permission_classes = (IsOwnerOrAuthenticatedReadOnly, )
    queryset = models.Tweet.objects.all()
    serializer_class = TweetSerializer


class ReadViewSet(viewsets.ModelViewSet):

    u""" User article reads.

    Holds the User data associated to articles, tweets and other “items”.
    """

    permission_classes = (IsOwnerOrAdminReadOnly, )
    queryset = models.Read.objects.all()
    serializer_class = ReadSerializer

    def get_queryset(self):
        """ Filter reads of current request user.

        .. todo:: use query filter if user is admin to get R/O
            reads of any user.
        """

        return self.queryset.filter(user_id=self.request.user.id)
