from django.db import models
from django.contrib.auth.models import User
from django.utils.html import escape
from django.db.models import Q
from datetime import date
from datetime import datetime
from MessagesApp.models import Thread
from BlockPages.models import BlockPage, BlockEvent, EventComment
from SpecialInfoApp.models import Interest, HasInterest, School, HasSchool, LivingLoc, HasLivingLoc, Workplace, HasWorkplace
from PostsApp.models import Comment
import helper_functions
import settings


# Create your models here.
class UserProfile(models.Model):
    #Required field
    user = models.ForeignKey(User, unique=True)

    #Extra inf
o
    
    #Enumerated data for columns that can only have a finite set of choices
    RELATIONSHIP_STATUSES = (
            (u'S', u'Single'),
            (u'M', u'Married'),
    )
    GENDER_CHOICES = (
            (u'M', u'Male'),
            (u'F', u'Female'),
            (u'B', u'Both'),
            (u'U', u'Unspecified'),

    )
    PRIVACY_CHOICES = (
            (u'p', u'Private'),
            (u'P', u'Public'),
    )

    #Define extra fields that will form the user profile
    relationship_status = models.CharField(max_length=2, choices=RELATIONSHIP_STATUSES, default=u'S')
    profile_pic = models.ForeignKey('userInfo.ImageHolder', null=True)
    birthday = models.DateField(null=True, blank=True)
    about_me = models.TextField(null=True)
    gender = models.CharField(max_length=2, choices=GENDER_CHOICES, default=u'U')
    interested_in = models.CharField(max_length=2, choices=GENDER_CHOICES, default=u'U')
    activity_privacy = models.CharField(max_length=2, choices=PRIVACY_CHOICES, default=u'P')
    latitude = models.FloatField(null=True)
    longitude = models.FloatField(null=True)
    current_block = models.ForeignKey(BlockPage,null=True)
    joined = models.DateTimeField(auto_now_add=True)
    last_login = models.DateTimeField(auto_now_add=True)
    threads = models.ManyToManyField(Thread, through='MessagesApp.ThreadMembership')
    events = models.ManyToManyField('BlockPages.BlockEvent')
    #Special info m2m's
    interests = models.ManyToManyField(Interest, through=HasInterest)
    living_locs = models.ManyToManyField(LivingLoc, through=HasLivingLoc)
    workplaces = models.ManyToManyField(Workplace, through=HasWorkplace)
    schools = models.ManyToManyField(School, through=HasSchool)
    
    ##########################################
    #Methods used to quickly get data about user in various formats
    def getName(self):
        """Returns string containing user's first and last name"""
        return self.user.first_name + ' ' + self.user.last_name

    def getInfo(self, user_2=None):
        """Returns dictionary object with basic info about this user"""
        if user_2 == None:
            relationship = 'No relation.'
        elif user_2 == self.id:
            relationship = 'This is you'
        else:
            relationship = self.getRelationshipTo(User.objects.get(pk=user_2).get_profile()).get_relationship_type_display()

        if self.profile_pic == None:
            profile_pic = 'default_profile.jpg'
        else:
            profile_pic = self.profile_pic.handle
        return { 'name' : self.getName(), 'email' : self.user.email, 
                'gender' : self.get_gender_display(), 'similarity' : 0 if user_2 == None else self.getSimilarityTo(user_2),
                'user_id' : self.user.id, 'username' : self.user.username, 'profile_pic' : profile_pic, 
                'thumbnail' : 'Thumbnails/' + profile_pic, 'relationship' : relationship }

    def getProfile(self, user_2=None):
        """Returns dictionary object containing detailed info about user suitable for the viewProfile view"""
        info = self.getInfo(user_2)
        info.update({ 'relationship_status' : self.get_relationship_status_display(), 
            'birthday' : 'Unspecified' if self.birthday == None else self.birthday.strftime("%m/%d/%Y"), 
            'interested_in' : self.get_interested_in_display(), 'about_me' : self.about_me, 'first_name' : self.user.first_name,
            'last_name' : self.user.last_name })
        
        return info

    def editProfile(self, request_dict):
        """Modifies info about self and self.user based on entered data in request_dict"""
        #For each field capable of being edited, make a try-except block
        try:
            new_rel_status = request_dict['relationship']

            #Validate input given RELATIONSHIP_STATUSES choices
            for rel in self.RELATIONSHIP_STATUSES:
                if new_rel_status == rel[0]:
                    self.relationship_status = rel[0]
                    self.save()
                elif new_rel_status == rel[1]:
                    self.relationship_status = rel[0]
                    self.save()
        except KeyError:
            pass
        
        #First name
        try:
            self.user.first_name = escape(request_dict['first_name'])
            self.user.save()
        except KeyError:
            pass

        #Last name
        try:
            self.user.last_name = escape(request_dict['last_name'])
            self.user.save()
        except KeyError:
            pass

        #Gender
        try:
            new_gender = request_dict['gender']

            #Validate input given GENDER_CHOICES choices
            for gen in self.GENDER_CHOICES:
                if new_gender == gen[0]:
                    self.gender = gen[0]
                    self.save()
                elif new_gender == gen[1]:
                    self.gender = gen[0]
                    self.save()
        except KeyError:
            pass

        #Interested in
        try:
            new_interested_in = request_dict['interested_in']

            #Validate input given GENDER_CHOICES choices
            for gen in self.GENDER_CHOICES:
                if new_interested_in == gen[0]:
                    self.interested_in = gen[0]
                    self.save()
                elif new_interested_in == gen[1]:
                    self.interested_in = gen[0]
                    self.save()
        except KeyError:
            pass


        #Birthday
        try:
            birthday = request_dict['birthday']

            #Validate input
            try:
                self.birthday = date(birthday['year'], birthday['month'], birthday['day'])
                self.save()
            except ValueError:
                #Invalid date
                pass
        except KeyError:
            pass

        #About me
        try:
            self.about_me = escape(request_dict['about_me'])
            self.save()
        except KeyError:
            pass

        #Not really sure how this method would fail
        return { 'success' : 1 }

    ##########################################
    #Methods relating to a user's friends
    def getFriends(self):
        """
        Returns list of this user's friends
        """
        try:
            return [e.user_2 for e in Relationship.objects.filter(user_1=self).filter(relationship_type__exact=u'F')] + [e.user_1 for e in Relationship.objects.filter(user_2=self).filter(relationship_type__exact=u'F')]
        except AttributeError:
            return []

    def getFriendRequests(self, trash=None):
        """Expects: nothing
           Returns: dictionary containing list of requesting friends' info, or error message"""
        try:
            return { 'requests' : [e.user_2.get_profile().getInfo(self.id) for e in Relationship.objects.filter(user_1=self).filter(relationship_type__exact=u'P')].extend([e.user_1.get_profile().getInfo(self.id) for e in Relationship.objects.filter(user_2=self).filter(relationship_type__exact=u'P')]), 'success' : 1 }
        except AttributeError:
            return { 'success' : 0, 'error' : 'Error getting friend requests.' }

    def getFriendDetails(self, user_2=None):
        """Returns list/array of dictionary objects for each friend w/ extra details"""
        return [friend.get_profile().getInfo(user_2) for friend in self.getFriends()]

    def requestFriend(self, request_dict):
        """Creates new Relationship object 