import json
import datetime
import twista
from dateutil import parser

class TweetObject:
    
    def __init__(self, json):
        self.json = json
        self.json['created_at'] = parser.parse(self.json['created_at']).isoformat()
        self.json['recorded_at'] = datetime.datetime.now(tz=datetime.timezone.utc).isoformat()
        
    def id(self):
        return self.json['id_str']
    
    def type(self):
        if (self.is_user()):
            return "user"
        if (self.is_status()):
            return "status" 
        if (self.is_retweet()):
            return "retweet" 
        if (self.is_quote()):
            return "quote" 
        if (self.is_reply()):
            return "reply"
        return "unknown"
    
    def created_at(self):
        return self.json['created_at']
    
    def recorded_at(self):
        return self.json['recorded_at']
    
    def user(self):
        return User(self.json['user'])
        
    def text(self):
        return self.json['text']
        
    def is_user(self):
        return "screen_name" in self.json

    def is_status(self):
        return not (self.is_quote() or self.is_reply() or self.is_retweet())
    
    def is_quote(self):
        return self.json['is_quote_status'] and "retweeted_status" not in self.json
    
    def is_reply(self):
        return self.json['in_reply_to_status_id_str'] != None
    
    def reply_to_status_id(self):
        return self.json['in_reply_to_status_id_str']
    
    def is_retweet(self):
        return "retweeted_status" in self.json
    
    def quote(self):
        if 'quoted_status' not in self.json:
            return None
        return Status(self.json['quoted_status'])
    
    def retweet(self):
        return Status(self.json['retweeted_status']) if self.is_retweet() else None
    
    def status(self):
        return Status(self.json)
    
    def __str__(self):
        return json.dumps(self.json, indent=4)
    
    
class Entities:
    
    def __init__(self, json):
        self.json = json
        
    def hashtags(self):
        return [e['text'] for e in self.json['hashtags']]

    def urls(self):
        return [e['url'] for e in self.json['urls']]
    
    def mentions(self):
        return [e['screen_name'] for e in self.json['user_mentions']]

    def mentioned_ids(self):
        res = [e['id_str'] for e in self.json['user_mentions']]
        return [r for r in res if r is not None]
    
    def as_dict(self):
        return {
            "hashtags": self.hashtags(),
            "urls": self.urls(),
            "mentions": self.mentions(),
            "mentioned_ids": self.mentioned_ids()         
        }
    
    def __str__(self):
        return json.dumps(self.as_dict(), indent=4)
        

    
class Status(TweetObject):
        
    def text(self):
        if 'extended_tweet' in self.json:
            return self.json['extended_tweet']['full_text']
        return self.json['text']
    
    def entities(self):
        if 'extended_tweet' in self.json:
            return Entities(self.json['extended_tweet']['entities'])
        return Entities(self.json['entities'])
    
    def as_dict(self):

        rts = self.json['retweet_count']
        favs = self.json['favorite_count']

        r = {
            'twista': twista.VERSION,
            "type": self.type(),
            "id": self.id(),
            "user": self.user().id(),
            "created_at": self.created_at(),
            "recorded_at": self.recorded_at(),
            "source": self.json['source'],
            "retweets": rts if rts else 0,
            "favourites": favs if favs else 0,
            "lang": self.json['lang']
        }

        r.update(self.entities().as_dict())

        if not self.is_retweet():
            r['text'] = self.text()

        if self.is_quote():
            r['refers_to'] = self.json['quoted_status_id_str']

        if self.is_retweet():
            r['refers_to'] = self.retweet().id()

        if self.is_reply():
            r['refers_to'] = self.reply_to_status_id()
            
        return r
    
    
class User(TweetObject):
                
    def screenname(self):
        return self.json['screen_name']
    
    def as_dict(self):
        return {
            'twista': twista.VERSION,
            'type': 'user',
            'id': self.id(),
            'screen_name': self.screenname(),
            'created_at': self.created_at(),
            'recorded_at': self.recorded_at(),
            'location': self.json['location'],
            'description': self.json['description'],
            'url': self.json['url'],
            'verified': self.json['verified'],
            # 'lang': self.json['lang'], deprecated meanwhile
            'followers': self.json['followers_count'],
            'friends': self.json['friends_count'],
            'listed': self.json['listed_count'],
            'favourites': self.json['favourites_count'],
            'statuses': self.json['statuses_count']
        }