from tastypie import fields
from tastypie.authentication import SessionAuthentication, MultiAuthentication
from account.authentication import MultiApiKeyAuthentication
from tastypie.validation import FormValidation
from tastypie.resources import ModelResource
from tastypie.authorization import Authorization
from tastypie.exceptions import Unauthorized

from cred.models import Cred, Tag, CredAudit
from cred.forms import TagForm


class CredAuthorization(Authorization):
    def read_list(self, object_list, bundle):
        # List views remove the deletes and historical credentials
        return object_list.filter(is_deleted=False, latest=None)

    def read_detail(self, object_list, bundle):
        # This audit should go somewhere else, is there a detail list function we can override?
        CredAudit(audittype=CredAudit.CREDPASSVIEW, cred=bundle.obj, user=bundle.request.user).save()
        return True

    def create_list(self, object_list, bundle):
        # Assuming their auto-assigned to ``user``.
        raise Unauthorized("Not yet implemented.")

    def create_detail(self, object_list, bundle):
        raise Unauthorized("Not yet implemented.")

    def update_list(self, object_list, bundle):
        raise Unauthorized("Not yet implemented.")

    def update_detail(self, object_list, bundle):
        raise Unauthorized("Not yet implemented.")

    def delete_list(self, object_list, bundle):
        # Sorry user, no deletes for you!
        raise Unauthorized("Not yet implemented.")

    def delete_detail(self, object_list, bundle):
        raise Unauthorized("Not yet implemented.")


class TagAuthorization(Authorization):
    def read_list(self, object_list, bundle):
        return object_list

    def read_detail(self, object_list, bundle):
        return True

    def create_list(self, object_list, bundle):
        # Assuming their auto-assigned to ``user``.
        raise Unauthorized("Not yet implemented.")

    def create_detail(self, object_list, bundle):
        return True

    def update_list(self, object_list, bundle):
        raise Unauthorized("Not yet implemented.")

    def update_detail(self, object_list, bundle):
        raise Unauthorized("Not yet implemented.")

    def delete_list(self, object_list, bundle):
        # Sorry user, no deletes for you!
        raise Unauthorized("Not yet implemented.")

    def delete_detail(self, object_list, bundle):
        raise Unauthorized("Not yet implemented.")


class CredResource(ModelResource):
    def get_object_list(self, request):
        # Only show latest, not deleted and accessible credentials
        return Cred.objects.accessible(request.user, historical=True, deleted=True)

    def dehydrate(self, bundle):
        # Workaround for this tastypie issue:
        # https://github.com/toastdriven/django-tastypie/issues/201
        bundle.data['username'] = bundle.obj.username

        # Add a value indicating if something is on the change queue
        bundle.data['on_changeq'] = bundle.obj.on_changeq()

        # The attachment field is irrelevant, hide it
        del bundle.data['attachment']

        # Unless you are viewing the details for a cred, hide the password
        if self.get_resource_uri(bundle) != bundle.request.path:
            del bundle.data['password']

        return bundle

    class Meta:
        queryset = Cred.objects.filter(is_deleted=False, latest=None)
        always_return_data = True
        resource_name = 'cred'
        excludes = ['username', 'is_deleted']
        authentication = MultiAuthentication(SessionAuthentication(), MultiApiKeyAuthentication())
        authorization = CredAuthorization()
        filtering = {
            'title': ('exact', 'contains', 'icontains'),
            'url': ('exact', 'startswith', ),
        }


class TagResource(ModelResource):
    # When showing a tag, show all the creds under it, that we are allowed to see
    creds = fields.ToManyField(CredResource,
        attribute=lambda bundle: Cred.objects.accessible(bundle.request.user).filter(tags=bundle.obj),
        null=True,
    )

    class Meta:
        queryset = Tag.objects.all()
        always_return_data = True
        filtering = {
            'name': ('exact', 'contains', 'icontains', 'startswith', 'istartswith'),
        }
        resource_name = 'tag'
        authentication = MultiAuthentication(SessionAuthentication(), MultiApiKeyAuthentication())
        authorization = TagAuthorization()
        validation = FormValidation(form_class=TagForm)
