"""Core DomoCard classes including federated and published support"""

__all__ = [
    "FederatedDomoCard",
    "DomoPublishCard",
    "DomoCard",
]

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

import httpx

from ...auth import DomoAuth
from ...base.entities_federated import DomoFederatedEntity
from ...client.context import RouteContext
from ..subentity.lineage import register_lineage_type
from .card_default import DomoCard_Default


@register_lineage_type("FederatedDomoCard", lineage_type="CARD")
@dataclass
class FederatedDomoCard(DomoCard_Default, DomoFederatedEntity):
    """Federated card seen in a parent instance; points to a child instance's native card.

    Inherits get_federated_parent() from DomoFederatedEntity base class.
    Use .Publish for all subscription operations.
    """

    @property
    def entity_type(self):
        return "CARD"

    @classmethod
    async def get_by_id(
        cls,
        auth: DomoAuth,
        card_id: str,
        optional_parts: str = "certification,datasources,drillPath,owners,properties,domoapp",
        check_if_published: bool = True,
        debug_api: bool = False,
        session: httpx.AsyncClient | None = None,
        return_raw: bool = False,
        is_suppress_errors: bool = False,
    ):
        """Retrieve federated card metadata"""
        # Use parent implementation to avoid code duplication
        return await super().get_by_id(
            auth=auth,
            card_id=card_id,
            optional_parts=optional_parts,
            check_if_published=check_if_published,
            debug_api=debug_api,
            session=session,
            return_raw=return_raw,
            is_suppress_errors=is_suppress_errors,
        )


@register_lineage_type("DomoPublishCard", lineage_type="CARD")
@dataclass
class DomoPublishCard(FederatedDomoCard):
    """Published card that supports publish/subscribe across instances.

    Use .Publish for all subscription operations:
        - card.Publish.ensure_subscription(retrieve_parent_auth_fn=fn)
        - card.Publish.get_parent_publication(parent_auth=auth)
        - card.Publish.get_publisher_entity(parent_auth=auth)
    """

    async def get_federated_parent(
        self,
        parent_auth: DomoAuth | None = None,
        parent_auth_retrieval_fn: Callable | None = None,
        *,
        context: RouteContext | None = None,
        **context_kwargs,
    ):
        """Get federated parent using publish helper for published cards.

        Args:
            parent_auth: Authentication for publisher instance
            parent_auth_retrieval_fn: Function to retrieve publisher auth by domain
            context: Route context for API calls
            **context_kwargs: Additional context parameters

        Returns:
            Publisher-side card entity

        Raises:
            ValueError: If publish helper is not configured or subscription not found
        """
        helper = self.enable_publish_support()

        await helper.ensure_subscription(
            retrieve_parent_auth_fn=parent_auth_retrieval_fn,
            parent_auth=parent_auth,
            entity_type="CARD",
            entity_id=str(self.id),
        )

        publisher_auth = await helper.get_publisher_auth(parent_auth=parent_auth)
        return await helper.get_publisher_entity(
            parent_auth=publisher_auth,
            context=context,
            **context_kwargs,
        )

    @classmethod
    async def get_entity_by_id(cls, auth: DomoAuth, entity_id: str, **kwargs):
        return await cls.get_by_id(auth=auth, card_id=entity_id, **kwargs)


@register_lineage_type("DomoCard", lineage_type="CARD")
@dataclass
class DomoCard(DomoCard_Default):
    """Smart factory class that returns appropriate card type based on metadata"""

    @classmethod
    def from_dict(
        cls,
        auth: DomoAuth,
        obj: dict,
        owners: list[Any] = None,
        is_published: bool = False,
        parent_auth_retrieval_fn: Callable | None = None,
        parent_auth: DomoAuth | None = None,
        **kwargs,
    ) -> "DomoCard":
        """Convert API response dictionary to appropriate card class instance.

        Args:
            auth: Authentication for the card's instance
            obj: API response dictionary
            owners: List of card owners
            is_published: Whether the card is published
            parent_auth_retrieval_fn: Function to retrieve publisher auth (for published cards)
            parent_auth: Publisher instance auth (for published cards)
            **kwargs: Additional arguments

        Returns:
            DomoCard instance (DomoPublishCard if published and federated)
        """

        is_federated = cls._is_federated(obj)

        new_cls = DomoCard

        if is_federated:
            # If federated AND published, return DomoPublishCard
            if is_published:
                new_cls = DomoPublishCard
            else:
                new_cls = FederatedDomoCard

        # Build the card instance with the appropriate class
        card = new_cls(
            auth=auth,
            id=obj.get("id"),
            raw=obj,
            title=obj.get("title"),
            description=obj.get("description"),
            type=obj.get("type"),
            urn=obj.get("urn"),
            certification=obj.get("certification"),
            chart_type=obj.get("metadata", {}).get("chartType"),
            dataset_id=(
                obj.get("datasources", [])[0].get("dataSourceId")
                if obj.get("datasources")
                else None
            ),
            owners=owners or [],
            datastore_id=obj.get("domoapp", {}).get("id"),
        )

        return card
