# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/classes/50_DomoPublish.ipynb.

# %% ../../nbs/classes/50_DomoPublish.ipynb 2
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Optional, List, Any
from domolibrary.client.DomoEntity import DomoEnum, DomoEntity_w_Lineage

import datetime as dt
import pandas as pd
import asyncio
import httpx

import uuid

from nbdev.showdoc import patch_to

import domolibrary.utils.DictDot as util_dd
import domolibrary.client.DomoAuth as dmda
import domolibrary.client.DomoEntity as dmen

import domolibrary.routes.publish as publish_routes

import domolibrary.classes.DomoLineage as dmdl

import domolibrary.utils.chunk_execution as dmce
import domolibrary.client.DomoError as dmde


# %% auto 0
__all__ = ['DomoPublication_Subscription', 'DomoPublication_Content_Enum', 'DomoPublication_Content',
           'DomoPublication_UnexpectedContentType', 'DomoPublication', 'DomoPublications']

# %% ../../nbs/classes/50_DomoPublish.ipynb 6
@dataclass
class DomoPublication_Subscription(dmen.DomoSubEntity):
    """the subscriber represents a location a publication is sent to"""


    subscription_id: str
    publication_id: str
    domain: str
    created_dt: Optional[dt.datetime] = (None,)


    @classmethod
    def _from_json(cls, obj, auth: dmda.DomoAuth, parent : Any= None):

        return cls(
            auth=auth,
            subscription_id=obj.get("id") or obj.get("subscriptionId"),
            publication_id=obj["publicationId"],
            domain=obj.get("domain") or obj.get("publisherDomain"),
            created_dt=(
                (dt.datetime.fromtimestamp(obj.get("created") / 1000))
                if obj.get("created")
                else None
            ),
            parent = parent,
            parent_id = (parent and parent.id) or None
        )

    async def get_content_details(
        self,
        debug_api: bool = False,
        debug_num_stacks_to_drop=2,
        session: httpx.AsyncClient = None,
    ):

        if not self.parent:
            raise dmde.DomoError(
                """The .parent attribute (DomoPublication) is required to get content details.
                must call from the publication instance.  Cannot call from the subscriber"""
            )
        
        publication_content = self.parent.content

        res = await publish_routes.get_subscriber_content_details(
            auth=self.auth,
            publication_id=self.publication_id,
            subscriber_instance=self.domain,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop,
            debug_api=debug_api,
            session = session,
            parent_class=self.__class__.__name__,
        )

        for content in publication_content:
            subscriber_obj = next(
                (
                    subscriber_obj
                    for subscriber_obj in res.response
                    if subscriber_obj["publisherObjectId"] == content.entity_id
                    and subscriber_obj["contentType"] == content.entity_type
                ),
                None,
            )
            if subscriber_obj is not None:
                content.subscriber_content_id = subscriber_obj["subscriberObjectId"]
                content.subscriber_insance = subscriber_obj["subscriberDomain"]

        self.content = publication_content

        return self.content

# %% ../../nbs/classes/50_DomoPublish.ipynb 9
class DomoPublication_Content_Enum(DomoEnum):
    import domolibrary.classes.DomoDataset as dmdc
    import domolibrary.classes.DomoCard as dmac
    import domolibrary.classes.DomoPage as dmpg
    import domolibrary.classes.DomoAppStudio as dmas

    CARD = dmac.DomoCard
    DATASET = dmdc.DomoDataset
    DATA_APP = dmas.DomoAppStudio
    PAGE = dmpg.DomoPage



# %% ../../nbs/classes/50_DomoPublish.ipynb 10
@dataclass
class DomoPublication_Content:
    auth: dmda.DomoAuth

    content_id: str
    entity_type: str
    entity_id: str
    entity_domain: str
    is_v2: bool
    is_direct_content: bool

    created_dt: dt.datetime
    updated_dt: dt.datetime = None

    subscriber_content_id: str = None
    subscriber_insance: str = None

    entity: Any = field(repr=False, default=None)
    parent: Any = field(repr=False, default=None)

    """the publication content is the content from the publisher instance that is being distributed to subscribers"""

    @classmethod
    def _from_json(cls, obj: dict, auth: dmda.DomoAuth, parent: Any = None):

        entity_type = obj.get("content").get("type")
        return cls(
            auth=auth,
            content_id=obj["id"],
            entity_id=obj.get("content").get("domoObjectId"),
            entity_domain=obj.get("content").get("domain"),
            is_v2=obj.get("isV2"),
            created_dt=(
                dt.datetime.fromtimestamp(obj["created"] / 1000)
                if obj["created"]
                else None
            ),
            updated_dt=(
                dt.datetime.fromtimestamp(obj.get("content").get("updated") / 1000)
                if obj.get("content").get("updated")
                else None
            ),
            is_direct_content=obj.get("useDirectContent"),
            parent=parent,
            entity_type=entity_type,
            entity=DomoPublication_Content_Enum[entity_type].value,
        )

    async def get_entity(self, debug_api: bool = False, session: httpx.AsyncClient = None):
        """get the entity from the publication content"""
        if not self.entity:
            self.entity=DomoPublication_Content_Enum[self.entity_type].value

        self.entity = await self.entity._get_entity_by_id(
            auth=self.auth,
            entity_id=self.entity_id,
            debug_api=debug_api,
            session = session
        )

        return self.entity

    def to_api_json(self):
        return {
            "domain": self.entity_domain,
            "domoObjectId": self.entity_id,
            "customerId": self.entity_domain,
            "type": self.entity_type,
        }

# %% ../../nbs/classes/50_DomoPublish.ipynb 12
class DomoPublication_UnexpectedContentType(dmde.ClassError):
    def __init__(self, cls_instance, content_type):
        super().__init__(
            cls_instance=cls_instance,
            message=f"DomoPublication_Instantiation: Unexpected content type {content_type}",
        )


@dataclass
class DomoPublication(DomoEntity_w_Lineage):
    auth: dmda.DomoAuth = field(repr=False)
    id: str
    Lineage: dmdl.DomoLineage_Publication = field(repr=False)

    name: str
    description: str
    is_v2: bool
    created_dt: dt.datetime

    updated_dt: dt.datetime = None

    subscription_authorizations: List[DomoPublication_Subscription] = None

    content: List[DomoPublication_Content] = None

    # content_page_id_ls: List[str] = default = None
    # content_dataset_id_ls: List[str] = field(default_factory=list)
    # content_data_app_id_ls: List[str] = field(default_factory=list)


    def __post_init__(self):
        self.Lineage = dmdl.DomoLineage_Publication._from_parent(parent=self, auth=self.auth)

    def _generate_subscription_authorizations(
        self, subscription_authorizations_ls, auth
    ):
        self.subscription_authorizations = [
            DomoPublication_Subscription._from_json(obj=sub, auth=auth, parent=self)
            for sub in subscription_authorizations_ls
        ]

    def _generate_content(self, children_ls):

        self.content = [
            DomoPublication_Content._from_json(child, auth=self.auth, parent=self)
            for child in children_ls
        ]

        # if dmpc.entity_type == "PAGE":
        #     domo_pub.content_page_id_ls.append(dmpc.entity_id)

        # elif dmpc.entity_type == "DATASET":
        #     domo_pub.content_dataset_id_ls.append(dmpc.entity_id)

        # elif dmpc.entity_type == "DATA_APP":
        #     domo_pub.content_data_app_id_ls.append(dmpc.entity_id)

        # else:
        #     raise DomoPublication_UnexpectedContentType(
        #         cls_instance=domo_pub,
        #         content_type=dmpc.entity_type,
        #     )

        return self.content

    @classmethod
    def _from_json(cls, obj, auth: dmda.DomoAuth):

        domo_pub = cls(
            id=obj["id"],
            name=obj["name"],
            description=obj["description"],
            created_dt=(
                dt.datetime.fromtimestamp(obj["created"] / 1000)
                if obj["created"]
                else None
            ),
            updated_dt=(
                dt.datetime.fromtimestamp(obj.get("content").get("updated") / 1000)
                if obj.get("content").get("updated")
                else None
            ),
            is_v2=obj["isV2"],
            auth=auth,
            raw = obj,
            Lineage = None
        )

        if (
            obj.get("subscriptionAuthorizations")
            and len(obj.get("subscriptionAuthorizations")) > 0
        ):
            domo_pub._generate_subscription_authorizations(
                subscription_authorizations_ls=obj["subscriptionAuthorizations"],
                auth=auth,
            )

        if obj.get("children") and len(obj.get("children")) > 0:
            domo_pub._generate_content(obj["children"])

        return domo_pub
    
    @classmethod
    async def get_by_id(
        cls,
        publication_id,
        auth: dmda.DomoAuth = None,
        return_raw: bool = False,
        timeout=10,
        debug_api: bool = False,
        debug_num_stacks_to_drop=2,
        session: httpx.AsyncClient = None,
    ):
        res = await publish_routes.get_publication_by_id(
            auth=auth,
            publication_id=publication_id,
            timeout=timeout,
            debug_api=debug_api,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop,
            session=session,
            parent_class=cls.__name__,
        )

        if return_raw:
            return res

        return cls._from_json(obj=res.response, auth=auth)
    
    @classmethod
    async def _get_entity_by_id(cls, entity_id, **kwargs):
        return await cls.get_by_id( publication_id = entity_id, **kwargs)
    
    def display_url(self):
        return f"https://{self.auth.domo_instance}.domo.com/admin/domo-everywhere/publications/details?id={self.id}"

# %% ../../nbs/classes/50_DomoPublish.ipynb 13
@patch_to(DomoPublication)
async def get_content(
    self,
    return_raw: bool = False,
    timeout=10,
    debug_api: bool = False,
    debug_num_stacks_to_drop=2,
    session: httpx.AsyncClient = None,
):
    res = await publish_routes.get_publication_by_id(
        auth=self.auth,
        publication_id=self.id,
        timeout=timeout,
        debug_api=debug_api,
        debug_num_stacks_to_drop=debug_num_stacks_to_drop,
        session=session,
        parent_class=self.__class__.__name__,
    )

    content = res.response.get('children')

    if return_raw:
        res.response = content
        return res
    

    if not content or len(content) == 0:
        return content
    
    return self._generate_content(content)


# %% ../../nbs/classes/50_DomoPublish.ipynb 21
@dataclass
class DomoPublications:
    auth: dmda.DomoAuth = field(repr = False)

    publications: List[DomoPublication] = field(default = None)

    subscriptions: List[DomoPublication_Subscription] = field(default = None)

    async def get(
        self,
        search_term: str = None,
        debug_api: bool = False,
        session: httpx.AsyncClient = None,
        return_raw: bool = False,
        debug_num_stacks_to_drop=2,
    ):

        res = await publish_routes.search_publications(
            auth=self.auth,
            debug_api=debug_api,
            session=session,
            search_term= search_term,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop,
            parent_class=self.__class__.__name__,
        )

        if return_raw:
            return res

        self.publications = await dmce.gather_with_concurrency(
            n=60,
            *[
                DomoPublication.get_by_id(
                    publication_id=obj.get("id"), auth=self.auth
                )
                for obj in res.response
            ],
        )
        return self.publications

    async def get_subscribers(
        self,
        session: httpx.AsyncClient = None,
        return_raw: bool = False,
        debug_api: bool = False,
    ):
        """get instances subscription summaries"""

        res = await publish_routes.get_subscription_summaries(
            auth=self.auth, session=session, debug_api=debug_api
        )

        if return_raw:
            return res

        self.subscriptions = [
            DomoPublication_Subscription._from_json(sub, auth=self.auth)
            for sub in res.response
        ]

        return self.subscriptions

# %% ../../nbs/classes/50_DomoPublish.ipynb 25
@patch_to(DomoPublications)
async def search_publications(
    self: DomoPublications,
    search_term: str = None,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    return_raw: bool = False,
    debug_num_stacks_to_drop = 2
):
    
    res = await self.get(
        search_term=search_term,
        session=session,
        debug_api=debug_api,
        return_raw = return_raw,
        debug_num_stacks_to_drop=debug_num_stacks_to_drop+1
    )

    return res

# %% ../../nbs/classes/50_DomoPublish.ipynb 27
@patch_to(DomoPublication)
async def report_content_as_dataframe(self, return_raw: bool = False):

    if return_raw:
        return await self.get_content()

    return pd.DataFrame(
        [
            {
                "plubication_id": self.id,
                "publication_name": self.name,
                "is_v2": self.is_v2,
                "publish_created_dt": self.created_dt,
                "entity_type": content.entity_type,
                "entity_id": content.entity_id,
                "entity_updated" : content.updated_dt
            }
            for content in self.content
        ]
    )


@patch_to(DomoPublication)
def report_lineage_as_dataframe(self, return_raw: bool = False):

    flat_lineage_ls = self.Lineage._flatten_lineage()

    output_ls = [
        {
            "plubication_id": self.id,
            "publication_name": self.name,
            "is_v2": self.is_v2,
            "publish_created_dt": self.created_dt,
            # "entity_type": row.get("entity_type"),
            "entity_id": row.get("entity_id"),
        }
        for row in flat_lineage_ls
    ]

    if return_raw:
        return output_ls

    return pd.DataFrame(output_ls)

# %% ../../nbs/classes/50_DomoPublish.ipynb 29
@patch_to(DomoPublication, cls_method=True)
async def create_publication(
    cls,
    name: str,
    content_ls: List[DomoPublication_Content],
    subscription_ls: List[DomoPublication_Subscription],
    unique_id: str = None,
    description: str = None,
    auth: dmda.DomoAuth = None,
    debug_api: bool = False,
):

    if not isinstance(subscription_ls, list):
        subscription_ls = [subscription_ls]

    auth = auth or cls.auth
    domain_ls = []
    content_json_ls = []
    for sub in subscription_ls:
        domain_ls.append(sub.domain)
    for content_item in content_ls:
        content_json_ls.append(content_item.to_api_json())

    if not unique_id:
        unique_id = str(uuid.uuid4())
    if not description:
        description = ""

    body = publish_routes.generate_publish_body(
        url=f"{auth.domo_instance}.domo.com",
        sub_domain_ls=domain_ls,
        content_ls=content_json_ls,
        name=name,
        unique_id=unique_id,
        description=description,
        is_new=True,
    )

    res = await publish_routes.create_publish_job(auth=auth, body=body)
    if debug_api:
        print("Create the new Publish job")
    if res.status != 200:
        print(res)
        await asyncio.sleep(2)
        res = await publish_routes.get_publication_by_id(
            auth=auth, publication_id=unique_id
        )
        if res.status != 200:
            return None
        else:
            return cls._from_json(obj=res.response, auth=auth)

    return cls._from_json(obj=res.response, auth=auth)

# %% ../../nbs/classes/50_DomoPublish.ipynb 31
@patch_to(DomoPublication)
async def update_publication(
    self,
    name: str,
    content_ls: List[DomoPublication_Content],
    subscription_ls: List[DomoPublication_Subscription],
    description: str = "",
    debug_api: bool = False,
):

    if not isinstance(subscription_ls, list):
        subscription_ls = [subscription_ls]

    domain_ls = [sub.domain for sub in subscription_ls]
    content_json_ls = [content_item.to_api_json() for content_item in content_ls]
        
    body = publish_routes.generate_publish_body(
        url=f"{self.auth.domo_instance}.domo.com",
        sub_domain_ls=domain_ls,
        content_ls=content_json_ls,
        name=name,
        unique_id=self.id,
        description=description,
        is_new=False,
    )

    res = await publish_routes.udpate_publish_job(
        auth=self.auth, publication_id=self.id, body=body
    )

    return res

# %% ../../nbs/classes/50_DomoPublish.ipynb 33
@patch_to(DomoPublication, cls_method=True)
async def get_subscription_invites_list(
    cls, auth: dmda.DomoAuth, debug_api: bool = False
):

    res = await publish_routes.get_subscription_invititations(
        auth=auth, debug_api=debug_api
    )
    if debug_api:
        print("Getting Publish subscription invites")

    if res.status == 200:
        return res.response
    else:
        return None


@patch_to(DomoPublication, cls_method=True)
async def accept_invite_by_id(
    cls, auth: dmda.DomoAuth, subscription_id: str, debug_api: bool = False
):

    res = await publish_routes.accept_invite_by_id(
        auth=auth, subscription_id=subscription_id, debug_api=debug_api
    )

    if res.status == 200:
        return res.response
    else:
        return None
