from __future__ import unicode_literals

import logging

from django.shortcuts import get_object_or_404
import django_filters

from rest_framework import exceptions
from rest_framework import filters as rf_filter
from rest_framework import mixins as rf_mixins
from rest_framework import permissions as rf_permissions
from rest_framework import viewsets as rf_viewsets
from rest_framework.decorators import action
from rest_framework.response import Response

from nodeconductor.cloud import models, serializers, tasks
from nodeconductor.core import viewsets, mixins
from nodeconductor.structure import filters as structure_filters
from nodeconductor.structure import models as structure_models


logger = logging.getLogger(__name__)


class FlavorViewSet(viewsets.ReadOnlyModelViewSet):
    """List of VM instance flavors that are accessible by this user.

    http://nodeconductor.readthedocs.org/en/latest/api/api.html#flavor-management
    """

    queryset = models.Flavor.objects.all()
    serializer_class = serializers.FlavorSerializer
    lookup_field = 'uuid'
    filter_backends = (structure_filters.GenericRoleFilter,)


class CloudViewSet(viewsets.ModelViewSet):
    """List of clouds that are accessible by this user.

    http://nodeconductor.readthedocs.org/en/latest/api/api.html#cloud-model
    """

    queryset = models.Cloud.objects.all().prefetch_related('flavors')
    serializer_class = serializers.CloudSerializer
    lookup_field = 'uuid'
    filter_backends = (structure_filters.GenericRoleFilter,)
    permission_classes = (rf_permissions.IsAuthenticated,
                          rf_permissions.DjangoObjectPermissions)

    def _check_permission(self, cloud):
        """
        Raises PermissionDenied exception if user does not have permission to cloud
        """
        if not self.request.user.is_staff and not cloud.customer.roles.filter(
                permission_group__user=self.request.user,
                role_type=structure_models.CustomerRole.OWNER,
        ).exists():
            raise exceptions.PermissionDenied()

    def pre_save(self, cloud):
        super(CloudViewSet, self).pre_save(cloud)
        self._check_permission(cloud)

    def post_save(self, obj, created=False):
        if created:
            tasks.sync_cloud_account.delay(obj.uuid.hex)

    def get_serializer_class(self):
        if self.request.method == 'POST':
            return serializers.CloudCreateSerializer

        return super(CloudViewSet, self).get_serializer_class()

    @action()
    def sync(self, request, uuid):
        """
        Starts cloud synchronization
        """
        cloud = get_object_or_404(models.Cloud, uuid=uuid)
        self._check_permission(cloud)
        cloud.sync()
        return Response({'status': "Cloud synchronization was scheduled"}, status=200)


class CloudProjectMembershipViewSet(rf_mixins.CreateModelMixin,
                                    rf_mixins.RetrieveModelMixin,
                                    rf_mixins.DestroyModelMixin,
                                    mixins.ListModelMixin,
                                    rf_viewsets.GenericViewSet):
    """
    List of project-cloud connections

    http://nodeconductor.readthedocs.org/en/latest/api/api.html#link-cloud-to-a-project
    """
    queryset = models.CloudProjectMembership.objects.all()
    serializer_class = serializers.CloudProjectMembershipSerializer
    filter_backends = (structure_filters.GenericRoleFilter,)
    permission_classes = (rf_permissions.IsAuthenticated, rf_permissions.DjangoObjectPermissions)

    def post_save(self, obj, created=False):
        if created:
            tasks.sync_cloud_membership.delay(obj.pk)


class SecurityGroupFilter(django_filters.FilterSet):
    name = django_filters.CharFilter(
        name='name',
    )
    description = django_filters.CharFilter(
        name='description',
        lookup_type='istartswith',
    )
    cloud = django_filters.CharFilter(
        name='cloud_project_membership__cloud__uuid',
    )
    project = django_filters.CharFilter(
        name='cloud_project_membership__project__uuid',
    )

    class Meta(object):
        model = models.SecurityGroup
        fields = [
            'name',
            'description',
            'cloud',
            'project'
        ]


class SecurityGroupViewSet(viewsets.ReadOnlyModelViewSet):
    """
    List of security groups

    http://nodeconductor.readthedocs.org/en/latest/api/api.html#security-group-management
    """
    queryset = models.SecurityGroup.objects.all()
    serializer_class = serializers.SecurityGroupSerializer
    lookup_field = 'uuid'
    permission_classes = (rf_permissions.IsAuthenticated,
                          rf_permissions.DjangoObjectPermissions)
    filter_class = SecurityGroupFilter
    filter_backends = (structure_filters.GenericRoleFilter, rf_filter.DjangoFilterBackend,)


class IpMappingFilter(django_filters.FilterSet):
    project = django_filters.CharFilter(
        name='project__uuid',
    )

    class Meta(object):
        model = models.IpMapping
        fields = [
            'project',
            'private_ip',
            'public_ip',
        ]


class IpMappingViewSet(viewsets.ModelViewSet):
    """
    List of mappings between public IPs and private IPs

    http://nodeconductor.readthedocs.org/en/latest/api/api.html#ip-mappings
    """
    queryset = models.IpMapping.objects.all()
    serializer_class = serializers.IpMappingSerializer
    lookup_field = 'uuid'
    filter_backends = (structure_filters.GenericRoleFilter, rf_filter.DjangoFilterBackend,)
    permission_classes = (rf_permissions.IsAuthenticated,
                          rf_permissions.DjangoObjectPermissions)
    filter_class = IpMappingFilter

@@ -3795,24 +3795,57 @@
 ame='name',%0A
+        lookup_type='icontains',%0A
     )%0A    de
@@ -3937,18 +3937,16 @@
 e='i
-startswith
+contains
 ',%0A 

Change security group filter type