from typing import Any, Optional, TYPE_CHECKING
from django.conf import settings
from django.contrib.auth import get_user_model

from ..models import SyncableModel
from .client import ConcordiaClient
from ..typehints import Record

if TYPE_CHECKING:
    from concordia_tests.latchstring.models import User
else:
    User = get_user_model()


# ---------------------------------------------------------------------------
def publish_concord_message(rooms: list[str], payload: dict) -> list[dict[Any, Any]]:
    """
    Helper method to publish a message to Concord MQ.
    """
    client = ConcordiaClient()
    results = []

    for room in rooms:
        result = client.publish(room=room, payload=payload)
        results.append(result)

    return results


# ---------------------------------------------------------------------------
def load_record(model: SyncableModel | None, cid: str, context: dict) -> Record:
    """
    Load model record from Concord MQ message data.

    If this is a Sync Publisher, load the User from the context,
    to ensure that the Subscriber User that published the message
    has access to the record.
    """
    # The Concordia client should fail registration if the user
    # is not found, but as a sanity check, ensure no perms are
    # granted if the User is not found.
    if not model or not (user := load_user_from_context(context)):
        return Record(None, None, False)  # type: ignore

    RecordModel = model

    # TODO consider some way of tracking the Publisher's user CID on Subscribers
    if not settings.SYNC_PUBLISHER:
        return Record(user, RecordModel.objects.filter(cid=cid).first(), True)

    # If the record exists and the user queried it successfully,
    # then the Subscriber user is permitted to publish changes.
    if record := RecordModel.objects.tenant(user).filter(cid=cid).first():  # type: ignore[attr-defined]
        return Record(user, record, True)

    # If untenanted query confirms the record doesn't exist, `create` operation is permissible.
    return Record(user, None, permitted=not RecordModel.objects.filter(cid=cid).exists())


# ---------------------------------------------------------------------------
def load_user_from_context(context: dict) -> Optional['User']:
    """
    Expects a context dict from a pghistory event.
    Return user object from context dict.
    """
    try:
        return User.objects.get(cid=context['user_cid'])
    except (KeyError, User.DoesNotExist):
        pass


__all__ = (
    'publish_concord_message',
    'load_record',
    'load_user_from_context',
)
