from typing import Optional, List, Dict
from dataclasses import dataclass

Url = str
Date = str
Html = str

StatusId = str
AccountId = str

@dataclass
class Account:
    id: AccountId
    username: str
    acct: str
    url: Url
    display_name: str
    
    note: Html
    
    avatar: Url
    avatar_static: Url
    
    header: Url
    header_static: Url
    
    locked: bool
    
    fields: List[Dict]
    emojis: List[Dict]
    
    bot: bool
    group: bool
    
    created_at: Date
    
    statuses_count: int
    followers_count: int
    following_count: int
    
    last_status_at: Optional[Date] = None
    
    discoverable: Optional[bool] = None
    noindex: Optional[bool] = None
    moved: Optional[bool] = None
    suspended: Optional[bool] = None
    limited: Optional[bool] = None
    

Card = Dict

MediaId = str
BlurHash = str

@dataclass
class MediaAttachment:
    """
    https://docs.joinmastodon.org/entities/MediaAttachment/
    """
    id: MediaId
    type: str
    url: Url
    preview_url: Url
    meta: Dict # Description: Metadata returned by Paperclip.
    
    blurhash: BlurHash
    
    description: Optional[str] = None # HACK: API doc doesn't say it can be null
    text_url: Optional[str] = None
    remote_url: Optional[Url] = None
    

@dataclass
class Status:
    id: StatusId
    uri: Url
    created_at: Date
    account: Account
    content: Html
    
    visibility: str
    sensitive: bool
    spoiler_text: str
    
    media_attachments: List[MediaAttachment]
    
    reblogs_count: int
    favourites_count: int
    replies_count: int
    
    url: Optional[Url] = None
    in_reply_to_id: Optional[StatusId] = None
    in_reply_to_account_id: Optional[AccountId] = None
    
    reblog: Optional['Status'] = None
    
    card: Optional[Card] = None
    
    text: Optional[str] = None
    
    edited_at: Optional[Date] = None
    
    favourited: Optional[bool] = None
    reblogged: Optional[bool] = None
    muted: Optional[bool] = None
    bookmarked: Optional[bool] = None
    pinned: Optional[bool] = None
    filtered: Optional[List['FilterMatch']] = None
    

Filter = Dict

@dataclass
class FilterMatch:
    filter: Filter
    keyword_matches: Optional[List[str]] = None
    status_matches: Optional[List[StatusId]] = None

@dataclass
class Context:
    ancestors: List[Status]
    descendants: List[Status]

ConversationId = str

@dataclass
class Conversation:
    id: ConversationId
    unread: bool
    accounts: List[Account]
    last_status: Optional[Status] = None


Tag = Dict

@dataclass 
class Search:
    accounts: List[Account]
    statuses: List[Status]
    hashtags: List[Tag]