from typing import TYPE_CHECKING

from django.conf import settings
from django.db.models import Model

if TYPE_CHECKING:
    from .channels import ConcordTriggerChannel


class RoomChannelRegistry(dict):
    """
    Map the base names of Concord MQ Rooms to PubSub Channel names.

    Concord MQ room names will have various forms for these use cases:
       * Console Subscribers POSTing local changes to Sync Server.
       * Sync Server deploying confirmed changes to Subscribers.

    This class should enable lookup of basic room names regardless
    of the room name form.
    """

    def __getitem__(self, key: str) -> 'ConcordTriggerChannel':
        """
        Extract the base room name from the full room path.
        """
        key = trim_publisher_prefix(key)
        try:
            return super().__getitem__(key)
        except KeyError:
            return super().__getitem__(trim_tenant_cid(key, self))

    def __setitem__(self, name: str, value: str) -> None:
        super().__setitem__(name, value)

    def room_subscriptions(self):
        """
        Get all room names that this Appliance tenant should subscribe to.
        """
        rooms = []

        for base_room_name, channel in self.items():
            subscribe_room_name = channel.subscribe_room_name()
            rooms.append(subscribe_room_name)
            rooms.append(f'{subscribe_room_name}/#')

        return rooms


def trim_publisher_prefix(room_name: str) -> str:
    """
    Room name may be prefixed with Willow Publisher name and Appliance Tenant CID.

    willow.compass/Person
    willow.compass/Person/779233ef-ace8-4698-92bf-3d4088c527cd
    """
    publisher_room_prefix = f'{settings.PUBLISHER_ROOM_PREFIX}/'
    try:
        if room_name.startswith(publisher_room_prefix):
            return room_name[len(publisher_room_prefix) :]
    except AttributeError:
        pass

    return room_name


def trim_tenant_cid(room_name: str, registry: dict) -> str:
    """
    Room name may have Tenant CID suffix.

    Person/779233ef-ace8-4698-92bf-3d4088c527c
    """
    try:
        if room_name.startswith(tuple(registry.keys())):
            return room_name[: room_name.find('/')]
    except AttributeError:
        pass

    return room_name


def base_tenanted_record_publish_rooms(record: Model, room: str) -> list[str]:
    """
    Subscribers establish Room based on their Appliance CID,
    so that each subscriber can be targeted specifically.
    Records will not necessarily belong on all Appliances, and
    we want to avoid sending messages to a Room unless the record
    definitively does belong there.

    Sync Publishers must broadcast record changes to the various Topics
    to which Sync Subscribers may be subscribed. This function should
    calculate all the Topics that may be interested in this record.

    Provide custom functionality by setting
    CONCORD_MQ_TENANTED_PUBLISH_ROOMS="path.to.your.function"
    """
    if not settings.SYNC_PUBLISHER:
        # The provided room string should be correctly formed to
        # publish the message from local Subscriber to remote Publisher.
        return [room]

    return []
