from users.serializers import *
from users.Utilities.Enums import *
from users.models import *

from datetime import datetime
import json

from django.db import transaction
from django.contrib.auth import authenticate, login, logout, get_user_model
from django.contrib.auth.models import Group
from django.contrib.auth.decorators import login_required
from django.http import QueryDict

from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
from rest_framework.response import Response

class Login(APIView):
	
	def post(self, request):		
		username = request.POST['username']
		password = request.POST['password']
		
		user = authenticate(username=username, password=password)
		if user is not None:
			if user.is_active:				
				login(request, user)				
				serializer = UserSerializer(user)
				return Response(serializer.data)
			else:
				return Response(status=status.HTTP_403_FORBIDDEN)
		else:
			return Response(status=status.HTTP_401_UNAUTHORIZED)

class Logout(APIView):
	permission_classes = (IsAuthenticated,)
	
	def get(self, request):
		logout(request)
		return Response(200)

class Register(APIView):
	
	def post(self, request):
		serialized = UserSerializer(data=request.DATA)
		if serialized.is_valid():
			user = get_user_model().objects.create_user(serialized.init_data['username'], email=serialized.init_data['email'], password=serialized.init_data['password'])
			return Response(serialized.data, status=status.HTTP_201_CREATED)
		else:
			return Response(serialized._errors, status=status.HTTP_400_BAD_REQUEST)


class Profile(APIView):
	permission_classes = (IsAuthenticated,)

	def get(self, request):
		"""
		Get user details
		"""
		u = get_user_model().objects.get(id=request.user.id)
		up, created = UserProfile.objects.get_or_create(user = u)
		
		serializer = UserProfileSerializer(up)
		return Response(serializer.data)
	
	def put(self, request):
		"""
		Update user details
		"""
		put = QueryDict(request.body)
		
		u = get_user_model().objects.get(id=request.user.id)
		up, created = UserProfile.objects.get_or_create(user = u)
		
		u.first_name = put.get('first_name')
		u.last_name = put.get('last_name')
		u.email = put.get('email')
		u.save()
		
		up.Company = put.get('company')
		
		country = put.get('country')
		if(country == ""):
			up.Country_id = None
		else:
			up.Country_id = country
		
		up.Blurb = put.get('blurb')
		up.DoB = put.get('dob')
		up.save()
		
		serializer = UserProfileSerializer(up)
		return Response(serializer.data)
		
	def post(self, request):
		"""
		Upload profile picture
		"""
		f = request.FILES['picture']
		filename = '/srv/HVD/static/img/users/' + request.user.username
		
		with open(filename, 'wb+') as destination:
			for chunk in f.chunks():
			    destination.write(chunk)
			    
		return Response(status=200)
	
	
class Password(APIView):
	permission_classes = (IsAuthenticated,)
	
	def put(self, request):
		"""
		Update password
		"""
		put = QueryDict(request.body)
		
		user = request.user
		
		if user.check_password(put.get('old_password')):
			user.set_password(put.get('new_password'))
			user.save()			
			return Response(status=200)
		else:
			return Response(status=401)
	
	
	def post(self, request):
		"""
		Reset password
		"""
		email = request.POST.get("email")
		user = get_user_model().objects.get(email=email)
		user.password_reset(request)
		
		return Response(status=200)
		
class Contacts(APIView):
	permission_classes = (IsAuthenticated,)

	def get(self, request):
		"""
		Fetch all contacts - user must be logged in
		"""
		contacts = Contact.objects.filter(UserProfileID=request.user.id)
		serializer = ContactSerializer(contacts, many=True)
		
		return Response(serializer.data)
	
	def delete(self, request, contact_id):
		"""
		Delete contact by contact_id
		"""
		contact = Contact.objects.get(pk=contact_id)
		contact.delete()
		
		return Response(status=200)
	
	def post(self, request):
		"""
		Add contact
		"""
		#parse POST json
		p = lambda:None
		p.__dict__ = json.loads(request.body)		
		
		with transaction.atomic():
			for username in p.users:
				#if the user does not already have this person as a contact, add them, else do nothing
				contacts = Contact.objects.filter(UserProfileID=request.user.id, ContactProfile__user__username=username)
				if len(contacts) < 1:		
					contact = UserProfile.objects.get(user__username=username)
					Contact.objects.create(UserProfileID=request.user.id, ContactProfile=contact, DateConnected=datetime.now())
			
					#notify the user that has been added
					nt = NotificationType.objects.get(pk=NotificationTypes.Added_As_Contact)
					Notification.objects.create(UserProfile=contact, Content=request.user.username + " added you as a contact", NotificationDate=datetime.now(), ViewedInd=False, NotificationType=nt)
		
		return Response(status=200)

class Conversations(APIView):
	permission_classes = (IsAuthenticated,)

	def post(self, request):
		"""
		Start a new conversation
		"""
		#parse POST json
		p = lambda:None
		p.__dict__ = json.loads(request.body)
		
		with transaction.atomic():
			dt = datetime.now()
			conversation = Conversation(Subject=p.subject, LastMessage=dt)
			conversation.save()			
			
			#add self to conversation
			profile = UserProfile.objects.get(user__id=request.user.id)				
			UserConversation.objects.create(Conversation=conversation, UserProfile=profile, DateJoined=dt, LastViewed=dt)
			
			#add message to conversation
			Message.objects.create(Conversation=conversation, Content=p.content, UserProfile=profile, Date=dt)
			
			#add other users to conversation
			for user in p.users:
				profile = UserProfile.objects.get(user__username=user)				
				UserConversation.objects.create(Conversation=conversation, UserProfile=profile, DateJoined=dt)
			
		return Response(status=200)
		
	
	def get(self, request, message_id):
		"""
		Fetch conversations if there have been new messages since message_id. If message_id is left blank, fetch all conversations.
		"""		
		if message_id:
			messages = Message.objects.filter(MessageID__gt=message_id)
			if len(messages) > 0:
				conversations = Conversation.objects.filter(UserConversations__UserProfile__user__id=request.user.id)
				serializer = ConversationSerializer(conversations, many=True)
				return Response(serializer.data)
			else:
				return Response("[]")
		else:
			conversations = Conversation.objects.filter(UserConversations__UserProfile__user__id=request.user.id)
			serializer = ConversationSerializer(conversations, many=True)
			return Response(serializer.data)


class Messages(APIView):
	permission_classes = (IsAuthenticated,)

	def get(self, request, conversation_id):
		"""
		Fetch a conversation. Returns all messages and the users who are part of the conversation.
		"""		
		conversation = Conversation.objects.get(ConversationID=conversation_id, UserConversations__UserProfile__user__id=request.user.id)
		
		uc = conversation.UserConversations.get(UserProfile__user__id=request.user.id)
		uc.LastViewed = datetime.now()
		uc.save()
		
		serializer = FullConversationSerializer(conversation)
		return Response(serializer.data)
		
	def post(self, request, conversation_id):
		"""
		Post a new message to a conversation
		"""
		p = lambda:None
		p.__dict__ = json.loads(request.body)
		
		profile = UserProfile.objects.get(user__id=request.user.id)	
		
		dt = datetime.now()
		con = Conversation.objects.get(pk=conversation_id, UserConversations__UserProfile__user__id=request.user.id)
		con.LastMessage = dt
		con.save()
		
		Message.objects.create(Content=p.content, UserProfile=profile, Date=dt, Conversation=con)
		
		return Response(status=200)
	

class Groups(APIView):
	permission_classes = (IsAuthenticated,)
	
	def get(self, request):
		"""
		Get all groups that you are a member of
		"""
		groups = request.user.groups.all()
		serializer = GroupSerializer(groups, many=True)
		return Response(serializer.data)
	
	
	def post(self, request):
		"""
		Create a group. The group creator automatically becomes a member of the group.
		"""
		p = lambda:None
		p.__dict__ = json.loads(request.body)
		
		with transaction.atomic():
			#Create the group
			group = Group(name=p.group_name)
			group.save()
			group.user_set.add(request.user)
			
			dt = datetime.now()
			
			#Create the group chat
			conversation = Conversation(Subject="Group Discussion: " + p.group_name, LastMessage=dt)
			conversation.save()			
			GroupConversation.objects.create(Group=group, Conversation=conversation)
			
			#Add the user to the group chat
			UserConversation.objects.create(UserProfile=request.user.userprofile, Conversation=conversation, DateJoined=dt, LastViewed=dt)
		
		return Response(status=200)

class GroupDetail(APIView):
	permission_classes = (IsAuthenticated,)

	def get(self, request, group_id):
		"""
		Get group details including group members, items shared with the group, and the group conversation
		"""
		g = Group.objects.get(id=group_id) 
		serializer = GroupDetailSerializer(g)
		return Response(serializer.data)
		
	def delete(self, request, group_id):
		"""
		Leave the group. If you are the only member left in the group, the group will be deleted.
		"""
		with transaction.atomic():
			g = Group.objects.get(id=group_id) 
			g.user_set.remove(request.user)
			
			uc = UserConversation.objects.get(UserProfile=request.user.userprofile, Conversation=g.groupconversation.Conversation);
			uc.delete()
			
			if len(g.user_set.all()) == 0:
				g.groupconversation.Conversation.delete()
				g.delete()
		
		return Response(status=200)
	
	def put(self, request, group_id):
		"""
		Invite users to a group by supplying a list of usernames
		"""
		p = lambda:None
		p.__dict__ = json.loads(request.body)
		
		with transaction.atomic():
			#Fetch the group
			group = Group.objects.get(pk=group_id)
			
			#Add each user to the group and the group chat
			for u in p.users:
				user = get_user_model().objects.get(username=u)
				group.user_set.add(user)
				dt = datetime.now()
				UserConversation.objects.create(UserProfile=user.userprofile, Conversation=group.groupconversation.Conversation, DateJoined=dt, LastViewed=dt)
				
				#notify the user that they have been added to a group
				nt = NotificationType.objects.get(pk=NotificationTypes.Added_To_Group)
				Notification.objects.create(UserProfile=user.userprofile, Content=request.user.username + " added you as the group '" + group.name + "'", NotificationDate=dt, ViewedInd=False, NotificationType=nt)
		
		
		return Response(status=200)
			
