from typing import List
from dataclasses import asdict, replace
from dacite import from_dict

import json

import requests

from mastodon_v2.types import Status, Conversation, Context

# https://github.com/mastodon/documentation/blob/master/content/en/api/guidelines.md#paginating-through-api-responses-pagination
class MastodonAPSource:
    def __init__ (self, endpoint, token):
        self.endpoint = endpoint
        self.token = token
        super().__init__()
        
    def get_status_collection (self, path,
        params = {}, return_dataclasses = False):
        
        url = self.endpoint + path
        params = {
            **params
        }
        
        headers = {}
        if self.token:
            headers.update({
               'Authorization': f'Bearer {self.token}'
            })
        
        response = requests.get(url, params=params, headers=headers)
        
        print(url)
        #print(response.status_code)
        #print(response.text)
        
        response_json = json.loads(response.text)
        
        try:
            print('trying to force timeline response to Status type')
            typed_resp = list(map(lambda s: from_dict(data=s, data_class=Status), response_json))
        except:
            raise 'error forcing status to type'
        
        if return_dataclasses:
            return typed_resp
        else:
            response_json = list(map(lambda s: asdict(s), typed_resp))
            
        return response_json

    def get_timeline (self, path = "home", params = {}, return_dataclasses=False):
        
        collection_path = "/api/v1/timelines/" + path
        params = {
            **params
        }
        
        return self.get_status_collection(collection_path, params = params, return_dataclasses=return_dataclasses)
        
    
    # nice parallel is validation
    # https://github.com/moko256/twitlatte/blob/master/component_client_mastodon/src/main/java/com/github/moko256/latte/client/mastodon/MastodonApiClientImpl.kt
    
    def get_mentions_timeline (self):
        # /api/v1/notifications?exclude_types=follow,favourite,reblog,poll,follow_request
        return
        
    def get_favorited_timeline (self):
        # /api/v1/notifications?exclude_types=follow,reblog,mention,poll,follow_request
        return
        
    def get_conversations (self,
            max_id = None, since_id = None, min_id = None, limit = None
            ) -> List[Conversation]:
        """
        Use get_status_context on the last_status for a conversation.
        """
        
        url = f'{self.instance}/api/v1/conversations'
        # https://docs.joinmastodon.org/methods/conversations/
        # Use HTTP Link header for pagination.
        headers = {
            'Authorization': f'Bearer {self.token}'
        }
        params = cleandict({
            'max_id': max_id,
            'since_id': since_id,
            'min_id': min_id,
            'limit': limit
        })
        
        resp = requests.get(url, params=params, headers=headers)
        response_json = json.loads(resp.text)
        conversations = list(map(lambda c: from_dict(data=c, data_class=Conversation), response_json))
        
        return conversations
    
    def get_status_context (self, status_id) -> Context:
        """
        Returns all parents and direct children.
        """
        url = f'{self.instance}/api/v1/statuses/{status_id}/context'
        headers = {
            'Authorization': f'Bearer {self.token}'
        }
        
        resp = requests.get(url, headers=headers)
        response_json = json.loads(resp.text)
        context = from_dict(data=response_json, data_class=Context)
        
        return context
    
    def get_bookmarks (self, 
        max_id=None, return_dataclasses=False):
        
        collection_path = '/api/v1/bookmarks'
        params = {}
        
        if max_id:
            params['max_id'] = max_id
        
        return self.get_status_collection(collection_path, params = params, return_dataclasses=return_dataclasses)
        
    def get_favorites_timeline (self):
        # /account/favourites
        return
    
    
    def get_user_statuses (self, account_id, 
        max_id = None, return_dataclasses=False):
        # /api/v2/search?type=statuses&account_id=
        # /api/v1/accounts/:id/statuses
        
        collection_path = f'/api/v1/accounts/{account_id}/statuses'
        
        params = {}
        
        if max_id:
            params['max_id'] = max_id
        
        return self.get_status_collection(collection_path, params = params, return_dataclasses=return_dataclasses)
    
    def get_statuses (self, ids):
        # /api/v1/statuses/:id
        return
        
    def get_profile (self, username):
        # /api/v1/accounts/search
        return self.search('@' + username, result_type='accounts')
        
    def search (q, result_type = None, following = False):
        # /api/v2/search
        return
        
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