from django.db.models import Q
from django.shortcuts import get_object_or_404

import django_filters
from rest_framework import serializers
from rest_framework.response import Response

from mozillians.api.v2.viewsets import NoCacheReadOnlyModelViewSet
from mozillians.common.templatetags.helpers import absolutify, markdown
from mozillians.common.urlresolvers import reverse
from mozillians.groups.models import Group, GroupMembership
from mozillians.users.managers import PUBLIC
from mozillians.users.models import ExternalAccount, IdpProfile, Language, UserProfile


# Serializers

class ExternalAccountSerializer(serializers.ModelSerializer):
    name = serializers.CharField(source='get_type_display')
    privacy = serializers.CharField(source='get_privacy_display')

    class Meta:
        model = ExternalAccount
        fields = ('type', 'identifier', 'privacy', 'name')

    def to_representation(self, instance):
        result = super(ExternalAccountSerializer, self).to_representation(instance)
        result['type'] = result['type'].lower()
        return result


class WebsiteSerializer(serializers.ModelSerializer):
    website = serializers.CharField(source='identifier')
    privacy = serializers.CharField(source='get_privacy_display')

    class Meta:
        model = ExternalAccount
        fields = ('website', 'privacy')


class LanguageSerializer(serializers.ModelSerializer):
    english = serializers.CharField(source='get_english')
    native = serializers.CharField(source='get_native')

    class Meta:
        model = Language
        fields = ('code', 'english', 'native')


class AlternateEmailSerializer(serializers.Serializer):
    email = serializers.SerializerMethodField()
    privacy = serializers.CharField(source='get_privacy_display')

    class Meta:
        model = ExternalAccount
        fields = ('email', 'privacy')

    def get_email(self, obj):
        if isinstance(obj, ExternalAccount):
            return obj.identifier
        if isinstance(obj, IdpProfile):
            return obj.email


class GroupSerializer(serializers.HyperlinkedModelSerializer):
    name = serializers.CharField()

    class Meta:
        model = Group
        fields = ('name', '_url')


class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
    username = serializers.ReadOnlyField(source='user.username')

    class Meta:
        model = UserProfile
        fields = ('username', 'is_vouched', '_url')


class UserProfileDetailedSerializer(serializers.HyperlinkedModelSerializer):
    username = serializers.ReadOnlyField(source='user.username')
    email = serializers.ReadOnlyField()
    photo = serializers.SerializerMethodField()
    alternate_emails = AlternateEmailSerializer(many=True, source='_api_alternate_emails')
    groups = GroupSerializer(many=True, source='_groups')
    country = serializers.SerializerMethodField()
    region = serializers.SerializerMethodField()
    city = serializers.SerializerMethodField()
    external_accounts = ExternalAccountSerializer(many=True, source='accounts')
    languages = LanguageSerializer(many=True)
    websites = WebsiteSerializer(many=True)
    is_public = serializers.ReadOnlyField()
    url = serializers.SerializerMethodField()

    # Add profile URL
    class Meta:
        model = UserProfile
        fields = ('username', 'full_name', 'email', 'alternate_emails', 'groups', 'bio', 'photo',
                  'ircname', 'date_mozillian', 'timezone', 'title', 'story_link', 'languages',
                  'external_accounts', 'websites', 'tshirt', 'is_public', 'is_vouched',
                  '_url', 'url', 'city', 'region', 'country')

    def _transform_privacy_wrapper(self, field):

        def _transform_privacy(obj, value):
            return {
                'value': value,
                'privacy': getattr(obj, 'get_privacy_{0}_display'.format(field))()
            }
        return _transform_privacy

    def __init__(self, *args, **kwargs):
        super(UserProfileDetailedSerializer, self).__init__(*args, **kwargs)

        # If we don't define a custom transform method and if the
        # field has a privacy setting, set the transform privacy
        # wrapper.

        for field in self.fields.keys():
            method_name = 'transform_{0}'.format(field)

            # Exclude `country`, `region`, `city` because they collide with the
            # field aliases for `geo_country`, `geo_city`, `geo_region`
            if field in ['country', 'region', 'city']:
                return None

            if ((not getattr(self, method_name, None)
                 and getattr(UserProfile, 'get_privacy_{0}_display'.format(field), None))):
                setattr(self, method_name, self._transform_privacy_wrapper(field))

    def get_url(self, obj):
        return absolutify(reverse('phonebook:profile_view',
                                  kwargs={'username': obj.user.username}))

    def transform_timezone(self, obj, value):
        return {
            'value': value,
            'utc_offset': obj.timezone_offset(),
            'privacy': obj.get_privacy_timezone_display(),
        }

    def transform_bio(self, obj, value):
        return {
            'value': value,
            'html': unicode(markdown(value)), # noqa
            'privacy': obj.get_privacy_bio_display(),
        }

    def get_photo(self, obj):
        return {
            'value': obj.get_photo_url('300x300'),