from channels.generic.websocket import WebsocketConsumer 
from .models import * 
import json
from django.template.loader import render_to_string
from asgiref.sync import async_to_sync
import threading



class OnlineUserConsumer(WebsocketConsumer):
    def connect(self):
        self.user = self.scope['user']
        existing_connection = Connection.objects.filter(user=self.user).last()
        if existing_connection:
            self.connection = existing_connection
            self.connection.online = True
            self.connection.disconnected = False
            self.connection.save()
        else:
            self.connection = Connection.objects.create(user=self.user, online=True)

        async_to_sync(self.channel_layer.group_add)(
            'online_users', self.channel_name
        )
        self.accept()
        self.modify_online_user()

    def disconnect(self, close_code):
        self.last_seen = datetime.now()
        self.connection.disconnected = True
        self.connection.save()
        timer_thread = threading.Timer(10, self.check_disconnect_status)
        timer_thread.start()

    def check_disconnect_status(self):
        connection = Connection.objects.filter(user=self.user).last()
        if connection.disconnected:
            self.connection.last_seen = self.last_seen
            self.connection.online = False
            self.connection.save()
        self.modify_online_user()

    def modify_online_user(self):
        cutoff_date = datetime.now() - timedelta(days=30)
        connections = Connection.objects.all()
        online_connections = connections.filter(online=True)
        offline_connections = connections.filter(online=False, last_seen__isnull=False, last_seen__gte=cutoff_date).order_by('-last_seen')
        sorted_connections = list(online_connections) + list(offline_connections)
        online_users_ids = [connection.user.id for connection in online_connections]
        customer_connections = []
        staff_connections = []
        for connection in sorted_connections:
            if hasattr(connection.user, 'customerprofile'):
                connection_data = {
                'first_name': connection.user.first_name,
                'last_name': connection.user.last_name,
                'last_seen': connection.user.customerprofile.get_last_seen,
                'online': connection.online
                }
                customer_connections.append(connection_data)
            elif hasattr(connection.user, 'staffprofile'):
                connection_data = {
                'first_name': connection.user.first_name,
                'last_name': connection.user.last_name,
                'last_seen': connection.user.staffprofile.get_last_seen,
                'image': connection.user.staffprofile.image.url,
                'online': connection.online
                }
                staff_connections.append(connection_data)

        event = {
            'type': 'online_user_connection_handler',
            'staff_connections': staff_connections,
            'customer_connections': customer_connections,
            'online_users_ids': online_users_ids
        }
        async_to_sync(self.channel_layer.group_send)(
            'online_users', event
        )

    def online_user_connection_handler(self, event):
        context = {
            'staff_connections': event['staff_connections'],
            'customer_connections': event['customer_connections'],
        }
        html = render_to_string("details_templates/partials/recently-online.html", context=context)
        self.send(text_data=json.dumps({
            'event_type': 'online_user_status',
            'html': html,
            'online_users_ids': event.get('online_users_ids', []) 
        }))



class NewStatusConsumer(WebsocketConsumer):
    def connect(self):
        self.user = self.scope['user']
        async_to_sync(self.channel_layer.group_add)(
            "new_status_group",
            self.channel_name
        )
        self.accept()

    def disconnect(self, close_code):
        async_to_sync(self.channel_layer.group_discard)(
            "new_status_group",
            self.channel_name
        )

    def new_status_event(self, event):
        is_online = Connection.objects.all().filter(user=self.user, online=True)
        status_id = event['status_id']
        status = Status.objects.get(id=status_id)
        context = {'status': status, 'new': True, 'is_online': is_online,}
        html = render_to_string("details_templates/partials/new-status-activity.html", context)
        self.send(text_data=json.dumps({
            'event_type': 'new_status',
                'html': html,
            }))




class UpdateStatusesTimeConsumer(WebsocketConsumer):
    def connect(self):
        self.user = self.scope['user']
        async_to_sync(self.channel_layer.group_add)(
            "new_statuses_time_group",
            self.channel_name
        )
        self.accept()
    def disconnect(self, close_code):
        async_to_sync(self.channel_layer.group_discard)(
            "new_statuses_time_group",
            self.channel_name
        )
    def receive(self, text_data):
        data = json.loads(text_data)
        connections = Connection.objects.filter(online=True)
        online_users_ids = [connection.user.id for connection in connections]
        if data.get('event_type') == 'update_statuses_time':
            event = {
                'type': 'modify_status_time_handler',
                'online_users_ids': online_users_ids,
            }
            async_to_sync(self.channel_layer.group_send)(
                "new_statuses_time_group", event
            )
    def modify_status_time_handler(self, event):
        today = datetime.now().date()
        latest_statuses = Status.objects.filter(date_time__date=today).order_by('-id')
        context = {'latest_statuses': latest_statuses}
        html = render_to_string("details_templates/partials/recent-activities.html", context)
        self.send(text_data=json.dumps({
            'event_type': 'update_statuses_time',
            'html': html,
            'online_users_ids': event.get('online_users_ids', []) 
            }))


