import logging

from ..util import api
from .collections import (DeletedRevs, Pages, RecentChanges, Revisions,
                          SiteInfo, UserContribs, Users)
from .errors import APIError, AuthenticationError, MalformedResponse

logger = logging.getLogger("mw.api.session")

DEFAULT_USER_AGENT = "MediaWiki-Utilities"
"""
The default User-Agent to be sent with requests to the API.
"""

class Session(api.Session):
    """
    Represents a connection to a MediaWiki API.
    
    Cookies and other session information is preserved.
    
    :Parameters:
        uri : str
            The base URI for the API to use.  Usually ends in "api.php"
        user_agent : str
            The User-Agent to be sent with requests.  Will raise a warning if
            left to default value.
    """
    
    def __init__(self, uri, *args, user_agent=DEFAULT_USER_AGENT, **kwargs):
        """
        Constructs a new :class:`Session`.
        """
        
        if user_agent == DEFAULT_USER_AGENT:
            logger.warning("Sending requests with default User-Agent.  "  +
                           "Set 'user_agent' on api.Session to quiet this " +
                           "message.")
        
        if 'headers' in kwargs:
            kwargs['headers']['User-Agent'] = str(user_agent)
        else:
            kwargs['headers'] = {'User-Agent': str(user_agent)}
        
        super().__init__(uri, *args, **kwargs)
        
        self.pages = Pages(self)
        """
        An instance of :class:`mw.api.Pages`.
        """
        
        self.revisions = Revisions(self)
        """
        An instance of :class:`mw.api.Revisions`.
        """
        
        self.recent_changes = RecentChanges(self)
        """
        An instance of :class:`mw.api.RecentChanges`.
        """
        
        self.site_info = SiteInfo(self)
        """
        An instance of :class:`mw.api.SiteInfo`.
        """
        
        self.user_contribs = UserContribs(self)
        """
        An instance of :class:`mw.api.UserContribs`.
        """
        
        self.users = Users(self)
        """
        An instance of :class:`mw.api.Users`.
        """
        
        self.deleted_revs = DeletedRevs(self)
        """
        An instance of :class:`mw.api.DeletedRevs`.
        """
        
    def login(self, username, password, token=None):
        """
        Performs a login operation.  This method usually makes two requests to
        API -- one to get a token and one to use the token to log in.  If
        authentication fails, this method will throw an
        :class:`.errors.AuthenticationError`.
        
        :Parameters:
            username : str
                Your username
            password : str
                Your password
        
        :Returns:
            The response in a json :py:class:`dict`
        """

        doc = self.post(
            {
                'action': "login",
                'lgname': username,
                'lgpassword': password,
                'lgtoken': token, # If None, we'll be getting a token
            }
        )
            
        
        try:
            if doc['login']['result'] == "Success":
                return doc
            elif doc['login']['result'] == "NeedToken":
                
                if token is not None:
                    # Woops.  We've been here before.  Better error out.
                    raise AuthenticationError(doc)
                else:
                    token = doc['login']['token']
                    return self.login(username, password, token=token)
            else:
                raise AuthenticationError(doc)
            
        except KeyError() as e:
            raise MalformedResponse(e.message, doc)
        
    
    def request(self, type, params, **kwargs):
        params.update({'format': "json"})
        
        doc = super().request(type, params, **kwargs).json()
        
        if 'error' in doc:
            raise APIError(doc)
        
        return doc
