from bottle import request, response
from itsdangerous.url_safe import URLSafeTimedSerializer
from cuchulu.libraries.keyutils import create_key_encrypt, create_key_encrypt_256, create_key

try:

    from settings import config

except ModuleNotFoundError:

    class config:
        cookie_name='cuchulu.session'
        key_encrypt=create_key_encrypt_256(30)
        session_opts={'session.data_dir': 'sessions', 'session.type': 'file', 'session.path': 'cuchulu'}
        
import inspect



class Session(dict):
    """Class for create sessions using itsdangerous library"""
    
    def __init__(self, *args, **kwargs):
        """Class for create sessions using itsdangerous library"""
        
        self.update(*args, **kwargs)
        
        self.changed=False
        
        self.safe=None
    
    def __setitem__(self, item, value):
        """Method for set items in session
        
        With this method, session instance set changed property for know that the session was changed and saved
        
        Args:
            item (str): The key of the session item
            value (mixed): The value of the session item
        
        """
        
        super(Session, self).__setitem__(item, value)
        self.changed=True
    
    def __delitem__(self, item):
        """Method for delete items in session
        
        With this method, session instance set changed property for know that the session was cleaning. 
        
        Args:
            item (str): The key of the session item
            value (mixed): The value of the session item
        
        """
        
        super(Session, self).__delitem__(item)
        self.changed=True
    
    # If use redirect or abort, you can save the session before of redirection
    
    def save(self):
        """Method for save the session
        
        When bottle make a redirect, directly make a raise exception and not save session. With this method you can save the session before the raise.
        """
        
        if self.changed:
            
            if not self.safe:
                self.safe=URLSafeTimedSerializer(config.key_encrypt)
            self.changed=False
            
            #if not max_age:
            response.set_cookie(config.cookie_name, self.safe.dumps(self), path=config.session_opts['session.path'], httponly=True)
    """
    def __del__(self):
        self.save()
        print('exit')
    """

def get_session():
    
    """Function for get the session from request object from bottle"""
    
    return request.environ.get('session', Session())

def session_plugin(callback):
    
    def wrapper(*args, **kwargs):
        
        cookie=request.get_cookie(config.cookie_name)
        
        safe=None
        
        if not cookie:
            session=Session()
        else:
            
            safe=URLSafeTimedSerializer(config.key_encrypt)
            try:
                session=Session(safe.loads(cookie))
                
                if type(session).__name__!='Session':
                    session=Session()
                
                session.safe=safe
                
            except:
                session=Session()
        
        if 'session' in kwargs:
            kwargs['session']=session
        
        #For compatibility with old sessions server-side style. 
        
        request.environ['session']=session
        
        rv=callback(*args, **kwargs)
        
        """
        if request.environ['session'].changed:
            
            if not safe:
                safe=URLSafeTimedSerializer(config.key_encrypt)
            
            #if not max_age:
            response.set_cookie(config.cookie_name, safe.dumps(session), path=config.session_opts['session.path'], httponly=True)
        """
        
        request.environ['session'].save()
            
        return rv
        
    return wrapper

#class SessionPlugin2(object):
    
    

class SessionPlugin(object):

    name = 'session'
    api = 2
    
    def __init__(self, keyword='session'):
        
        self.keyword=keyword
        self.session={}

        
    def setup(self, app):
        ''' Make sure that other installed plugins don't affect the same keyword argument.'''
        for other in app.plugins:
            if not isinstance(other, SessionPlugin): continue
            if other.keyword == self.keyword:
                raise PluginError("Found another login plugin with "\
                "conflicting settings (non-unique keyword).")

    def apply(self, callback, context):

        # Test if the original callback accepts a 'session' keyword.
        # Ignore it if it does not need a login handle.
        
        conf = context.config.get(self.keyword) or {}
        
        keyword = conf.get('keyword', self.keyword)
        
        args = inspect.getfullargspec(context.callback)[0]
        
        """
        if keyword not in args:
            return callback
        """
        if keyword in args:
            #print(args[keyword])
            self.session[callback.__name__]=True
        else:
            self.session[callback.__name__]=False
            #print(callback.__name__)
        
        def wrapper(*args, **kwargs):
            
            cookie=request.get_cookie(config.cookie_name)
            
            safe=None
            
            if not cookie:
                session=Session()
            else:
                
                safe=URLSafeTimedSerializer(config.key_encrypt)
                try:
                    session=Session(safe.loads(cookie))
                    
                    if type(session).__name__!='Session':
                        session=Session()
                    
                except:
                    session=Session()
            
            #if 'session' in kwargs:
            #print(kwargs)
            
            if self.session[callback.__name__]:
                kwargs['session']=session
            
            #For compatibility with old sessions server-side style. 
            
            request.environ['session']=session
            
            request.environ['session'].changed=False
            
            rv=callback(*args, **kwargs)
            
            #if request.environ['session'].changed:
            
            request.environ['session'].save()
            
            """
            if session.changed:
                #print('changed')
                if not safe:
                    safe=URLSafeTimedSerializer(config.key_encrypt)
                
                #if not max_age:
                response.set_cookie(config.cookie_name, safe.dumps(session), path=config.session_opts['session.path'], httponly=True)
            """
                
            return rv

        return wrapper
            
                    
        



