"""
    Implementation of the syndication taxonomy in architecture.md
"""

from dataclasses import dataclass, asdict, replace
from typing import List, Dict, Optional, Tuple, Union

import re

@dataclass
class ContentId:
    prefix: str
    id: str
    
    def __str__ (self):
        return self.prefix + self.id
    
    @staticmethod
    def parse (content_id, prefix, id_pattern = '(.+)'):
        raw_id = content_id[len(prefix):]
        id_matches = re.fullmatch(id_pattern, raw_id)
        if id_matches:
            raw_id = id_matches[0]
            return ContentId(prefix=prefix, id=raw_id)
    
@dataclass
class PublicMetrics:
    reply_count: Optional[int] = None
    quote_count: Optional[int] = None
    retweet_count: Optional[int] = None
    like_count: Optional[int] = None
    impression_count: Optional[int] = None
    bookmark_count: Optional[int] = None
    
    
    # may be video only
    view_count: Optional[int] = None
    
    
    def items (self):
        return asdict(self).items()
    
@dataclass
class NonPublicMetrics:
    impression_count: Optional[int] = None
    user_profile_clicks: Optional[int] = None
    url_link_clicks: Optional[int] = None
    
    def items (self):
        return asdict(self).items()

@dataclass
class MediaItem:
    type: str
    preview_image_url: str
    
    media_key: Optional[str] = None
    image_url: Optional[str] = None
    
    url: Optional[str] = None
    content_type: Optional[str] = None
    duration_ms: Optional[int] = None
    
    height: Optional[int] = None
    width: Optional[int] = None
    
    size: Optional[int] = None
    
    public_metrics: Optional[PublicMetrics] = None

@dataclass
class Card:
    display_url: Optional[str] = None
    source_url: Optional[str] = None
    content: Optional[str] = None
    title: Optional[str] = None
    preview_image_url: Optional[str] = None
    image_url: Optional[str] = None


@dataclass
class FeedItemAction:
    route: str
    route_params: Dict

# intended as external resources,
# not first class display.
# PDF, chat, embedded image (iframe)
@dataclass
class FeedItemAttachment:
    name: str
    content_type: str
    
    url: Optional[str] = None
    content: Optional[object] = None
    
    size: Optional[int] = None

@dataclass
class UnrepliedSection:
    feed_item_id: Optional[str] = None
    description: Optional[str] = None
    text: Optional[str] = None
    span: Optional[Tuple[int, int]] = None
    
    def text_from (self, feed_item: 'FeedItem') -> str:
        if not self.span or not feed_item.text:
            return
        
        return feed_item.text[self.span[0]:self.span[1]]

ReplyingToSection = UnrepliedSection

@dataclass
class FeedItem:
    id: str
    created_at: str
    
    display_name: str
    handle: str
    
    published_by: Optional['FeedServiceUser'] = None
    
    title: Optional[str] = None
    text: Optional[str] = None
    html: Optional[str] = None
    
    author_is_verified: Optional[bool] = None
    url: Optional[str] = None
    conversation_id: Optional[str] = None
    
    avi_icon_url: Optional[str] = None
    
    author_url: Optional[str] = None
    author_id: Optional[str] = None
    
    source_url: Optional[str] = None
    source_author_url: Optional[str] = None
    
    reply_depth: Optional[int] = 0
    
    is_marked: Optional[bool] = None
    is_bookmarked: Optional[bool] = None
    
    card: Optional[Card] = None
    
    public_metrics: Optional[PublicMetrics] = None
    non_public_metrics: Optional[NonPublicMetrics] = None
    
    retweeted_tweet_id: Optional[str] = None
    
    source_retweeted_by_url: Optional[str] = None
    retweeted_by: Optional[str] = None
    retweeted_by_url: Optional[str] = None
    
    videos: Optional[List[MediaItem]] = None
    photos: Optional[List[MediaItem]] = None
    
    quoted_tweet_id: Optional[str] = None
    quoted_tweet: Optional['FeedItem'] = None
    
    replied_tweet_id: Optional[str] = None
    replied_tweet: Optional['FeedItem'] = None
    
    note: Optional[str] = None
    
    debug_source_data: Optional[Dict] = None
    
    attachments: Optional[List[FeedItemAttachment]] = None
    
    # At some point we may move to feed_item_actions when the set is known
    actions: Optional[Dict[str, FeedItemAction]] = None
    
    # This is a TBD concept to highlight unreplied parts of a message.
    unreplied: Optional[List[UnrepliedSection]] = None
    
    # This is a TBD concept to highlight parts of a message that are a reply.
    replying_to: Optional[List[ReplyingToSection]] = None
    
    is_viewed: Optional[bool] = None

# tm = FeedItem(id="1", text="aa", created_at="fs", display_name="fda", handle="fdsafas")


@dataclass
class ThreadItem:
    feed_item: Union[FeedItem,'Collection','RoutedMessage']
    children: Optional[List['ThreadItem']] = None
    parent: Optional['ThreadItem'] = None
    parents: Optional[List['ThreadItem']] = None
    
    actions: Optional[Dict[str, FeedItemAction]] = None
    


@dataclass
class FeedServiceUser:
    id: str
    url: str
    name: str # display_name
    username: str # handle
    
    is_verified: Optional[bool] = None
    is_protected: Optional[bool] = None
    
    created_at: Optional[str] = None
    description: Optional[str] = None
    preview_image_url: Optional[str] = None # deprecated... rename to avatar_image_url
    poster_image_url: Optional[str] = None
    website: Optional[str] = None
    location: Optional[str] = None
    
    actions: Optional[Dict[str, FeedItemAction]] = None 
    
    source_url: Optional[str] = None
    
    raw_user: Optional = None
    
    @property
    def display_name (self) -> str:
        return self.name
        
    @property
    def handle (self) -> str:
        return self.username
        
    @property
    def avatar_image_url (self) -> str:
        return self.preview_image_url


@dataclass
class Collection:
    """
    Works for both collections and lists for now
    """
    id:str
    name: str
    
    description: Optional[str] = None
    preview_image_url: Optional[str] = None
    
    created_at: Optional[str] = None
    updated_at: Optional[str] = None
    
    owner_id: Optional[str] = None
    owner: Optional[FeedServiceUser] = None
    
    url: Optional[str] = None
    
    total_count: Optional[int] = None
    
    current_page: Optional['CollectionPage'] = None



@dataclass
class CollectionItem:
    item: List[Union[FeedServiceUser,FeedItem,ThreadItem,Collection]] = None
    sort_order: Optional[int] = None
    after_id: Optional[str] = None

@dataclass
class CollectionPage:
    """
    Works for Collections and Lists for now, as well as Threads and nested Collections.
    
    Feed is a Collection.
    """
    
    id: str
    items: Optional[List[Union[FeedServiceUser,FeedItem,ThreadItem,CollectionItem,Collection]]] = None
    next_token: Optional[str] = None
    last_dt: Optional[str] = None
    total_count: Optional[int] = None
    
    includes: Optional[Dict] = None




def cleandict(d):
    if isinstance(d, dict):
        return {k: cleandict(v) for k, v in d.items() if v is not None}
    elif isinstance(d, list):
        return [cleandict(v) for v in d]
    else:
        return d
