import logging
from typing import Optional, Type, Union

from django.dispatch import receiver
from django.db.models import signals
from staff.audit.factory import create_log as create_audit_log

from staff.map.signals import equipment_updated, room_updated
from staff.map.signals import conference_room_updated, table_updated

from .models import FloorMap, Table, Device, Room
from .models.logs import LogFactory, LogAction
from .utils import update_floor_img
from ..person.models import Staff


def map_signal_handler(signal):
    @receiver(signal)
    def handle_map_object_action(sender, author: Staff, obj, action, **kw):
        create_audit_log(
            objects=[obj],
            who=author.user,
            action=action,
            primary_key=obj.pk
        )

        cls: Optional[Union[Type[Table], Type[Room], Type[Device]]] = None
        log_action: Optional[LogAction] = None

        if action == 'table_created':
            log_action = LogAction.CREATED
            cls = Table

        elif action == 'table_location_updated':
            log_action = LogAction.UPDATED
            cls = Table

        elif action == 'table_deleted':
            log_action = LogAction.DELETED
            cls = Table

        elif action == 'equipment_created':
            log_action = LogAction.CREATED
            cls = Device

        elif action == 'equipment_updated':
            log_action = LogAction.UPDATED
            cls = Device

        elif action == 'equipment_disabled':
            log_action = LogAction.DISABLED
            cls = Device

        elif action in ('room_created', 'conference_room_created'):
            log_action = LogAction.CREATED
            cls = Room

        elif action in ('room_updated', 'conference_room_updated'):
            log_action = LogAction.UPDATED
            cls = Room

        elif action in ('room_deleted', 'conference_room_deleted'):
            # not a typo, see usages: it's disabled, not deleted
            log_action = LogAction.DISABLED
            cls = Room

        if log_action:
            if isinstance(obj, cls):  # type: ignore
                LogFactory.create_log(who=author.user, obj=obj, action=log_action)
            else:
                logger = logging.getLogger('staff.map.handlers')
                logger.error(
                    'Mismatch between signal action %s and obj #%s class %s skipping map logs.',
                    action,
                    obj.pk,
                    type(obj),
                )

    return handle_map_object_action


@receiver(signal=signals.post_save, sender=FloorMap)
def floormap_updated(sender, **kwargs):
    update_floor_img(kwargs['instance'])


@receiver(signal=signals.post_delete, sender=FloorMap)
def floormap_deleted(sender, **kwargs):
    update_floor_img(kwargs['instance'])


handle_equipment_updated = map_signal_handler(equipment_updated)
handle_room_updated = map_signal_handler(room_updated)
handle_conference_room_updated = map_signal_handler(conference_room_updated)
handle_table_updated = map_signal_handler(table_updated)
