class MemberSerializer(serializers.ModelSerializer):
    """Member serializer - handles all data serialization
    for the Member model"""
    unique_artists = serializers.SerializerMethodField('calc_unique_artists')
    listen_count = serializers.SerializerMethodField('calc_listen_count')
    loved_tracks = serializers.PrimaryKeyRelatedField(
        many=True, read_only=True, required=False)

    def calc_unique_artists(self, obj):
        scrobbles = Scrobble.objects.filter(member=obj.id)
        return scrobbles.values_list('song__artist__id').distinct().count()

    def calc_listen_count(self, obj):
        return Scrobble.objects.filter(member=obj.id).count()

    def update(self, instance, validated_data):
        for attr, value in validated_data.items():
            if attr == 'password':
                instance.set_password(value)
            else:
                setattr(instance, attr, value)
            instance.save()
            return instance

    class Meta:
        model = Member
        exclude = ('email', 'password', 'listened_to') class CreateMemberSerializer(serializers.Serializer):
    nick_name = serializers.CharField(validators=[alpha_only])
    username = serializers.CharField(validators=[alpha_only])
    email = serializers.CharField()
    password = serializers.CharField()

    def create(self, validated_data):
        passwd = validated_data.pop('password', None)
        user_name = validated_data.pop('username', None)
        mail = validated_data.pop('email', None)
        nick = validated_data.pop('nick_name', None)

        does_exist = Member.objects.filter(nick_name__iexact=nick)
        if len(does_exist) > 0:
            return

        instance = Member(
                email=mail,
                username=user_name,
                nick_name=nick)
        if passwd is not None:
            instance.set_password(passwd)
        instance.save()
        social = MemberInfo.objects.create(belongs_to=instance)
        return instance class FollowingSerializer(serializers.ModelSerializer):
    belongs_to = serializers.StringRelatedField()
    following = serializers.StringRelatedField(many=True)

    class Meta:
        model = Following
        fields = '__all__' class FollowerSerializer(serializers.Serializer):
    belongs_to = serializers.CharField() class MemberInfoSerializer(serializers.ModelSerializer):

    class Meta:
        model = MemberInfo
        fields = '__all__' class ShoutSerializer(serializers.ModelSerializer):

    class Meta:
        model = Shout
        fields = '__all__' class Member(AbstractUser):
    """Member(user) model. Abstracted from Django user accounts"""
    nick_name = models.CharField(max_length=60, unique=True)
    loved_tracks = models.ManyToManyField(Song, blank=True)

    listened_to = models.ManyToManyField(
        Song, blank=True, related_name='listened_to')

    profile_picture = models.ImageField(
        upload_to='cdn/images/avatars/', null=True, blank=True)

    # DECEMBAWEEEEEEEEEEEEEEEN
    banner_picture = models.ImageField(
        upload_to='cdn/images/banners/', null=True, blank=True)

    def __str__(self):
        return self.nick_name class Following(models.Model):
    following = models.ManyToManyField(Member, related_name='sender')
    belongs_to = models.ForeignKey(Member, on_delete=models.CASCADE)

    def __str__(self):
        return 'People {} follows'.format(self.belongs_to.nick_name) class MemberInfo(models.Model):
    """Holds member social links, bio, etc"""
    bio = models.CharField(
        max_length=200, default='I haven\'t wrote a bio!', null=True)
    github = models.CharField(max_length=100, null=True, blank=True)
    twitter = models.CharField(max_length=100, null=True, blank=True)
    reddit = models.CharField(max_length=100, null=True, blank=True)
    youtube = models.CharField(max_length=140, null=True, blank=True)
    belongs_to = models.OneToOneField(Member, on_delete=models.CASCADE)

    def __str__(self):
        return self.belongs_to.nick_name class Shout(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(Member, on_delete=models.CASCADE)
    shouted_to = models.ForeignKey(Member, related_name='shouted_to', on_delete=models.CASCADE)
    text = models.CharField(max_length=200)

    def __str__(self):
        return '{} -> {}'.format(created_by, shouted_to) class Scrobble(models.Model):
    """Scrobbles model to specifically handle all
    Artist data/storage within the Scrobbles app"""
    song = models.ForeignKey(Song, on_delete=models.CASCADE)
    member = models.ForeignKey(Member, on_delete=models.CASCADE)
    date_scrobbled = models.DateTimeField()

    def __str__(self):
        # e.x "Hells Bells, AC/DC - Admin"
        return '{}, {} - {}'.format(self.song.title,
                                    self.song.artist.name,
                                    self.member.nick_name) class UserFilter(BaseFilterBackend):

    def filter_queryset(self, request, queryset, view):
        q = request.query_params.get
        user = request.user
        query = queryset

        if q('listened'):
            query = query.filter(
                    listened_to__artist__name__iexact=q('listened')).distinct()
        return query class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    Custom permission to only allow owners of an object to edit it.
    """

    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Write permissions are only allowed to the owner of the snippet.
        return obj.member == request.user class IsUserOrReadOnly(permissions.BasePermission):

    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True

        return obj == request.user
from operator import itemgetter
from collections import defaultdict
from django.contrib.auth.hashers import make_password
from django.http import HttpResponseRedirect
from django.db.models import Count
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.authtoken.models import Token
from rest_framework import permissions
from users.serializers import MemberSerializer, CreateMemberSerializer, \
    FollowingSerializer, FollowerSerializer, MemberInfoSerializer, \
    ShoutSerializer
from users.models import Member, Following, MemberInfo, Shout
from scrobbles.models import Scrobble
from .filters import UserFilter
from WeebFM.permissions import IsOwnerOrReadOnly, IsUserOrReadOnly
"""User views file. Contains all viewsets/routes for the Users app"""



class MemberInfoView(viewsets.ModelViewSet):
    """Social links for a user. User foreign keys to this"""
    queryset = MemberInfo.objects.all()
    serializer_class = MemberInfoSerializer
    permission_classes = (
        permissions.IsAuthenticatedOrReadOnly,
        IsOwnerOrReadOnly
    )

    @action(detail=True, methods=['GET', 'PATCH'])
    def nick(self, request, pk=None):
        if request.method == 'GET':
            resp = MemberInfo.objects.get(belongs_to__nick_name__iexact=pk)
            serializer = MemberInfoSerializer(instance=resp)
            return Response(serializer.data)
        elif request.method == 'PATCH':
            obj = MemberInfo.objects.get(belongs_to__nick_name__iexact=pk)
            d = request.data
            if 'github' in d:
                obj.github = d['github']
            if 'twitter' in d:
                obj.twitter = d['twitter']
            if 'reddit' in d:
                obj.reddit = d['reddit']
            if 'bio' in d:
                obj.bio = d['bio']
            obj.save()
            serializer = MemberInfoSerializer(instance=obj)
            return Response(serializer.data)


class MemberView(viewsets.ModelViewSet):
    """Member viewset - handles all Member
    related routes/post-creation tasks"""
    queryset = Member.objects.all()
    serializer_class = MemberSerializer
    permission_classes = (IsUserOrReadOnly,)
    filter_backends = (UserFilter,)

    def get_serializer_class(self):
        if self.action == 'create':
            return CreateMemberSerializer
        return MemberSerializer

    @action(detail=False, methods=['GET'])
    def current(self, request):
        try:
            user = Member.objects.get(id=self.request.user.id)
            serializer = self.get_serializer(user)
            return Response(serializer.data)
        except:
            return Response(status=status.HTTP_404_NOT_FOUND)

    @action(detail=False, methods=['GET'])
    def most_scrobbles(self, request):
        users = []

        total_scrobbles = Scrobble.objects.all().count()