"""a class based approach for interacting with Domo Datasets"""

__all__ = [
    "DomoDataset_Default",
    "FederatedDomoDataset",
    "DomoPublishDataset",
    "DomoDatasetView",
    "DomoDataset",
]


from collections.abc import Callable
from dataclasses import dataclass

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 .dataset_default import DomoDataset_Default
from .view import DomoDatasetView


@register_lineage_type("FederatedDomoDataset", lineage_type="DATA_SOURCE")
@dataclass
class FederatedDomoDataset(DomoDataset_Default, DomoFederatedEntity):
    """Federated dataset seen in a parent instance; points to a child instance's native dataset.

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

    @classmethod
    async def get_by_id(
        cls,
        auth: DomoAuth,
        dataset_id: str,
        debug_api: bool = False,
        return_raw: bool = False,
        session: httpx.AsyncClient | None = None,
        debug_num_stacks_to_drop: int = 2,
        is_use_default_dataset_class: bool = False,
        parent_class: str | None = None,
        is_suppress_no_account_config: bool = True,
    ):
        """retrieves federated dataset metadata"""
        # Use parent implementation to avoid code duplication
        return await super().get_by_id(
            dataset_id=dataset_id,
            auth=auth,
            debug_api=debug_api,
            return_raw=return_raw,
            session=session,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop,
            is_use_default_dataset_class=is_use_default_dataset_class,
            parent_class=parent_class or cls.__name__,
            is_suppress_no_account_config=is_suppress_no_account_config,
        )


@register_lineage_type("DomoPublishDataset", lineage_type="DATA_SOURCE")
@dataclass
class DomoPublishDataset(FederatedDomoDataset):
    """Published dataset that supports publish/subscribe across instances.

    Use .Publish for all subscription operations:
        - dataset.Publish.ensure_subscription(retrieve_parent_auth_fn=fn)
        - dataset.Publish.get_parent_publication(parent_auth=auth)
        - dataset.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 datasets.

        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 dataset 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="DATA_SOURCE",
            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(id=entity_id, auth=auth, **kwargs)


@register_lineage_type("DomoDataset", lineage_type="DATA_SOURCE")
@dataclass
class DomoDataset(DomoDataset_Default):
    @classmethod
    def from_dict(
        cls,
        auth: DomoAuth,
        obj: dict,
        # is_admin_summary: bool = True,
        check_is_published: bool = None,
        is_use_default_dataset_class: bool = False,
        new_cls=None,
        is_published: bool = False,
        parent_auth_retrieval_fn: Callable | None = None,
        parent_auth: DomoAuth | None = None,
        **kwargs,
    ) -> "DomoDataset":
        """Factory method that automatically detects the dataset type and returns
        the appropriate class:
        - DomoDatasetView for views (dataset-view)
        - DomoPublishDataset for published federated datasets
        - FederatedDomoDataset for federated datasets
        - DomoDataset for regular datasets

        Args:
            auth: Authentication for the dataset's instance
            obj: API response dictionary
            check_is_published: Whether to check if dataset is published
            is_use_default_dataset_class: Force use of base DomoDataset class
            new_cls: Specific class to use (overrides auto-detection)
            is_published: Whether the dataset is published
            parent_auth_retrieval_fn: Function to retrieve publisher auth (for published datasets)
            parent_auth: Publisher instance auth (for published datasets)
            **kwargs: Additional arguments

        Returns:
            DomoDataset instance (appropriate subclass based on type)
        """

        is_federated = cls._is_federated(obj)
        is_view = cls._is_view(obj)

        new_cls = DomoDataset

        # Check if it's a view first (views can also be federated)
        if is_view and not is_use_default_dataset_class:
            new_cls = DomoDatasetView
        elif is_federated and not is_use_default_dataset_class:
            # If federated AND published, return DomoPublishDataset
            if check_is_published:
                new_cls = DomoPublishDataset
            else:
                new_cls = FederatedDomoDataset

        return super().from_dict(
            auth=auth,
            obj=obj,
            is_use_default_dataset_class=is_use_default_dataset_class,
            new_cls=new_cls,
            **kwargs,
        )

    @classmethod
    async def get_by_id(
        cls,
        auth: DomoAuth,
        dataset_id: str,
        debug_api: bool = False,
        return_raw: bool = False,
        session: httpx.AsyncClient | None = None,
        debug_num_stacks_to_drop: int = 2,
        is_use_default_dataset_class: bool = False,
        parent_class: str | None = None,
        is_get_account: bool = True,
        is_suppress_no_account_config: bool = True,
        check_if_published: bool = True,
        parent_auth_retrieval_fn: Callable | None = None,
        parent_auth: DomoAuth | None = None,
        max_subscriptions_to_check: int | None = None,
    ):
        """Retrieve dataset metadata by ID.

        This method uses the factory pattern in from_dict() to automatically
        return the appropriate dataset class (DomoDatasetView, FederatedDomoDataset, etc.)
        based on the dataset metadata.
        """
        # Delegate to parent class which has the published check logic
        return await super().get_by_id(
            auth=auth,
            dataset_id=dataset_id,
            debug_api=debug_api,
            return_raw=return_raw,
            session=session,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop,
            is_use_default_dataset_class=is_use_default_dataset_class,
            parent_class=parent_class or cls.__name__,
            is_get_account=is_get_account,
            is_suppress_no_account_config=is_suppress_no_account_config,
            check_if_published=check_if_published,
            parent_auth_retrieval_fn=parent_auth_retrieval_fn,
            parent_auth=parent_auth,
            max_subscriptions_to_check=max_subscriptions_to_check,
        )
