from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass, field
from typing import Any

from ..auth.base import DomoAuth
from ..client.context import RouteContext
from .entities import DomoEntity_w_Lineage


@dataclass
class DomoFederatedEntity(DomoEntity_w_Lineage):
    """Entity that can be federated across multiple Domo instances.

    This class extends lineage-enabled entities to support federation,
    allowing entities to maintain relationships across different Domo
    instances in federated environments.

    Provides a default implementation of get_federated_parent() that works
    by querying subscriptions on the subscriber instance and matching the
    entity to publications on publisher instances.
    """

    __skip_lineage_registration__ = True  # Abstract intermediate class, not registered

    parent_entity: Any = field(default=None, repr=False)

    async def get_federated_parent(
        self,
        parent_auth: DomoAuth | None = None,
        parent_auth_retrieval_fn: Callable | None = None,
        *,
        context: RouteContext | None = None,
        **context_kwargs,
    ):
        """Retrieve the parent entity from a federated Domo instance.

        This default implementation:
        1. Gets all subscriptions for the subscriber instance
        2. Fetches publication details from each publisher
        3. Matches this entity to the published content

        Args:
            parent_auth: Authentication object for the parent instance
            parent_auth_retrieval_fn: Function to retrieve parent auth by domain

        Returns:
            The parent entity from the publisher instance

        Raises:
            ClassError: If the parent entity cannot be found
        """
        from ..classes.DomoEverywhere import DomoEverywhere
        from ..utils import chunk_execution as dmce
        from .exceptions import ClassError

        domo_everywhere = DomoEverywhere(auth=self.auth)
        await domo_everywhere.get_subscriptions()

        await dmce.gather_with_concurrency(
            *[
                sub.get_parent_publication(
                    parent_auth_retrieval_fn=parent_auth_retrieval_fn,
                    parent_auth=parent_auth,
                )
                for sub in domo_everywhere.subscriptions
            ],
            n=20,
        )

        all_matches = await dmce.gather_with_concurrency(
            *[
                sub.parent_publication.get_publication_entity_by_subscriber_entity(
                    subscriber_domain=sub.subscriber_domain,
                    subscriber=self,
                )
                for sub in domo_everywhere.subscriptions
            ],
            n=20,
        )

        self.parent_entity = next(
            (entity for entity in all_matches if entity is not None), None
        )

        if not self.parent_entity:
            # Get entity name - try common fields
            entity_name = (
                getattr(self, "name", None)
                or getattr(self, "title", None)
                or "N/A"
            )
            subscriber_instance = getattr(self.auth, "domo_instance", "unknown")
            publisher_instance = (
                getattr(parent_auth, "domo_instance", "unknown")
                if parent_auth
                else "unknown"
            )

            raise ClassError(
                cls_instance=self,
                message=(
                    f"Unable to retrieve federated parent entity for '{entity_name}' (ID: {self.id}). "
                    f"The most likely cause is that the publisher entity has not been shared with the user "
                    f"authenticated on the subscriber instance '{subscriber_instance}'. "
                    f"Please verify that:\n"
                    f"  1. The entity is published from publisher instance '{publisher_instance}'\n"
                    f"  2. The entity is included in a publication that is subscribed to by '{subscriber_instance}'\n"
                    f"  3. The user authenticated with '{subscriber_instance}' has access to the published entity"
                ),
            )

        return self.parent_entity
