from datetime import datetime
from typing import Any, Dict, List, Optional

from pydantic import BaseModel as Base


class Entries(Base):
    """Contains metadata parsed from the text contents of the tweet.

    This object is a subclass of the pydantic BaseModel which makes it easy to serialize
    the object with the .dict() and json() methods.

    Attributes:
        hashtags: Contains all hashtags parsed from the tweet. Example #Bitcoin.
        cashtags: Contains all cashtags parsed from the tweet. Example $BTC
        urls: Contains all URLs parsed from the tweet excluding photo/video media links.
        photos: Contains all URLs that link to photo media.
        videos: Contains all URLs that link to video media.
    """

    hashtags: List[str]
    cashtags: List[str]
    urls: List[str]
    photos: List[str]
    videos: List[str]


class Tweet(Base):
    """Represents a status update from a twitter user.

    This object is a subclass of the pydantic BaseModel which makes it easy to serialize
    the object with the .dict() and json() methods.

    Attributes:
        tweet_id: Twitter assigned id associated with the tweet.
        tweet_url: Twitter assigned url that links to the tweet.
        is_retweet: Represents if the tweet is a retweet.
        is_pinned: Represents if the user has pinned the tweet.
        time: Time the user sent the tweet.
        text: Text contents of the tweet.
        replies: A count of the replies to the tweet.
        retweets: A count of the times the tweet was retweeted.
        likes: A count of the times the tweet was liked.
        entries: Contains the entries object which holds metadata
            on the tweets text contents.

    """

    tweet_id: int
    tweet_url: str
    username: str
    # user_id: int # unable to parse from nitter.
    is_retweet: bool
    is_pinned: bool
    time: datetime
    text: str
    replies: int
    retweets: int
    likes: int
    entries: Entries

    @classmethod
    def from_dict(cls, elements: Dict[str, Any]) -> "Tweet":
        """Creates Tweet object from a dictionary of processed text elements.

        Args:
            elements: Preprocessed attributes of a tweet object.

        Returns:
            Tweet object.

        """
        return cls(**elements)


class Profile(Base):
    """The profile object contains Twitter User account metadata.

    This object is a subclass of the pydantic BaseModel which makes it easy to serialize
    the object with the .dict() and json() methods.

    Attributes:
        username: The users screen_name, handle or alias. '@dgnsrekt'
        name: The users name as they've defined it.
        profile_photo: URL reference to the profiles photo.
        tweets_count: The number of Tweets (including retweets) issued by the user.
        following_count: The number of accounts the user is following.
        followers_count: The number of followers this account has.
        likes_count: Number of likes the follower has received.
        is_verified: Indicates if the user has been verified.
        banner_photo: URL reference to the profiles banner.
        biography: The users autobiography.
        user_id: User identification number generated by twitter.
        location: A user defined location.
        website: A user defined website.

    """

    username: str
    name: str
    # birthday: str #NOTE: need to find a twitter page with birthday to parse.
    profile_photo: str
    tweets_count: int
    following_count: int
    followers_count: int
    likes_count: int
    is_verified: bool
    # is_private: bool

    banner_photo: Optional[str] = None
    biography: Optional[str] = None
    user_id: Optional[int] = None
    location: Optional[str] = None
    website: Optional[str] = None

    @classmethod
    def from_dict(cls, elements: Dict[str, Any]) -> "Profile":
        """Creates Profile object from a dictionary of processed text elements.

        Args:
            elements: Preprocessed attributes of a profile object.

        Returns:
            Profile object.

        """
        return cls(**elements)
