from channels.generic.websocket import WebsocketConsumer
from asgiref.sync import async_to_sync
from .models import ChatMemberModel, ChatMessageModel
from profiles.models import BlockModel

import time
import json

class ChatConsumer(WebsocketConsumer):

	def connect(self):

		user = self.scope["user"]
		if (user.is_anonymous or not user.is_authenticated):
			return

		channel_id : int = int(self.scope['url_route']['kwargs']['chat_id'])

		if ChatMemberModel.objects.filter(member_id=user.pk, channel_id=int(channel_id)).count() != 1:
			return

		if (self.channel_layer == None):
			return

		self.room_group_name = f'chat{channel_id}'

		async_to_sync(self.channel_layer.group_add)(
			self.room_group_name,
			self.channel_name
		)

		self.accept()


	def receive(self, text_data=None, bytes_data=None):

		if text_data == None:
			return

		user = self.scope["user"]
		if (user.is_anonymous or not user.is_authenticated):
			return

		text_data_json: dict = json.loads(text_data)
		
		message = text_data_json.get('message')
		if (message is None):
			return
		
		receivers_id = text_data_json.get('receivers_id')
		if (receivers_id is None):
			return

		channel_id : int = int(self.scope['url_route']['kwargs']['chat_id'])

		if ChatMemberModel.objects.filter(member_id = user.pk, channel_id = channel_id).count() != 1:
			return

		if (self.channel_layer == None):
			return

		message_time: int = int(time.time() * 1000)
		
		if (len(receivers_id) == 1 and 
			BlockModel.objects.filter(blocker=user.pk, blocked=receivers_id[0]) or
			BlockModel.objects.filter(blocker=receivers_id[0], blocked=user.pk)
			):
			return

		async_to_sync(self.channel_layer.group_send)(
			self.room_group_name,
			{
				'type':'chat_message',
				'author_id':user.pk,
				'content':message,
				'time':message_time,
			}
		)
		
		new_message = ChatMessageModel(
				channel_id = channel_id, 
				author_id = user.pk, 
				content = message, 
				time = message_time
		).save()

	def chat_message(self, event):

		user = self.scope["user"]
		if (user.is_anonymous or not user.is_authenticated):
			return

		channel_id: int = int(self.scope['url_route']['kwargs']['chat_id'])

		if ChatMemberModel.objects.filter(member_id=user.pk, channel_id=channel_id).count() != 1:
			return

		self.send(text_data=json.dumps({
			'type':'chat',
			'author_id':event['author_id'],
			'content':event['content'],
			'time': event['time'],
		}))

class ChatNoticeConsumer(WebsocketConsumer):

	def connect(self):

		user = self.scope["user"]
		#if (user.is_anonymous or not user.is_authenticated):
			#return

		if (self.channel_layer == None):
			return

		self.room_group_name = f'chatNotice{user.pk}'
		if (not hasattr(self.channel_layer, "users_channels")):
			self.channel_layer.users_channels = {}
		self.channel_layer.users_channels[user.pk] = self.channel_name

		if (not hasattr(self.channel_layer, "invite")):
			self.channel_layer.invite = {}
		self.channel_layer.invite[user.pk] = [];

		async_to_sync(self.channel_layer.group_add)(
			self.room_group_name,
			self.channel_name
		)

		self.accept()

		message_time: int = int(time.time() * 1000)
		targets = list(self.channel_layer.users_channels.keys())
		for target in targets:
			channel = self.channel_layer.users_channels.get(target)
			if (channel == None or target == user.pk):
				continue
			async_to_sync(self.channel_layer.send)(channel, {
				'type':"online_users",
				'author_id':user.pk,
				'time':message_time,
			})

	def disconnect(self, code):

		user = self.scope["user"]
		if (user.is_anonymous or not user.is_authenticated):
			return	

		self.channel_layer.users_channels.pop(user.pk)

		message_time: int = int(time.time() * 1000)

		targets = list(self.channel_layer.users_channels.keys())
		for target in targets:
			channel = self.channel_layer.users_channels.get(target)
			if (channel == None or target == user.pk):
				continue
			async_to_sync(self.channel_layer.send)(channel, {
				'type':"online_users",
				'author_id':user.pk,
				'time':message_time,
			})

	def receive(self, text_data=None, bytes_data=None):

		if text_data == None:
			return

		user = self.scope["user"]
		#if (user.is_anonymous or not user.is_authenticated):
			#return

		text_data_json = json.loads(text_data)
		
		type_notice = text_data_json.get('type')
		targets : list = text_data_json.get('targets')
		content : dict = text_data_json.get('content')

		if (type_notice == None or targets == None):
			return

		if (self.channel_layer == None):
			return

		message_time: int = int(time.time() * 1000)
		status = 200;

		#print("receive" + str(user.pk))

		if targets == "all":
			targets = list(self.channel_layer.users_channels.keys())

		for target in targets:
			channel = self.channel_layer.users_channels.get(target)
			if (channel == None or target == user.pk):
				if (channel == None):
					status = 404
				continue
			async_to_sync(self.channel_layer.send)(channel, {
				'type':type_notice,
				'author_id':user.pk,
				'content':content,
				'time':message_time,
				'status': 200,
			})
		async_to_sync(self.channel_layer.send)(self.channel_layer.users_channels.get(user.pk), {
			'type':type_notice,
			'author_id':user.pk,
			'content':"notice return",
			'time':message_time,
			'status':status,
		})



	def invite(self, event):

		user = self.scope["user"]
		if (user.is_anonymous or not user.is_authenticated):
			return

		if (self.channel_layer.invite[event["author_id"]].get(user.pk)):
			return
		self.channel_layer.invite[event["author_id"]].append(user.pl)

		self.send(text_data=json.dumps({
			'type':event['type'],
			'author_id':event['author_id'],
			'content':event['content'],
			'time': event['time'],
			'status':event['status'],
		}))

	def online_users(self, event):

		user = self.scope["user"]
		#if (user.is_anonymous or not user.is_authenticated):
			#return

		#print("online_users" + str(user.pk))

		event['content'] = self.channel_layer.users_channels

		self.send(text_data=json.dumps({
			'type':event['type'],
			'author_id':event['author_id'],
			'content':event['content'],
			'time': event['time'],
			'status':event['status'],
		}))
