import os, sys, traceback, inspect, resource
from importlib import import_module
from bottle import route, get, post, run, default_app, abort, request, response, static_file, load, hook, error, debug, redirect, template
from settings import config

from mimetypes import guess_type
from cuchulu.libraries.db.webmodel import WebModel
from cuchulu.libraries.datetime import set_timezone

from cuchulu.libraries.keyutils import create_key_encrypt, create_key_encrypt_256, create_key
from cuchulu.wsgiapp import app

try:
    from settings import modules as modules_external
    
except:
    class modules_external:
        extra_apps={}

modules_pass=False

#app.reset()

#from cuchulu.libraries.sessions import generate_session

#Prepare links for static.
#WARNING: only use this feature in development, not in production.

workdir=os.getcwd()
arr_module_path={}

"""
if config.session_enabled==True:
    #Create dir for sessions
    
    if 'session.data_dir' in config.session_opts:
        
        if not os.path.isdir(config.session_opts['session.data_dir']):
            os.makedirs(config.session_opts['session.data_dir'], 0o700, True)

"""

error_reporting=False

if hasattr(config, 'error_reporting'):
    error_reporting=config.error_reporting

def prepare_app():
    
    # In mod_wsgi, make strange thing with reloading.
    
    app.reset()

    def print_memory():
        print(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)

    routes={}

    module_loaded=None

    app_mounts={}
    
    if len(modules_external.extra_apps)>0:
        config.apps=config.apps | modules_external.extra_apps
    
    for key_app, added_app in config.apps.items():
        
        controller_path=import_module(added_app[0])
        
        controller_base=os.path.dirname(controller_path.__file__)
        #print(controller_base)
        dir_controllers=os.listdir(controller_base)
        
        for controller in dir_controllers:

            if controller.endswith('.py') and controller.find('__init__')==-1:
                    
                controller_py=controller.replace('.py', '')
                
                module_app=added_app[0]+'.'+controller_py

                a=import_module(module_app)
                
                if added_app[1]!='':
                
                    if controller_py=='app':
                
                        app_name=getattr(a, added_app[1])
                        
                        if not added_app[2] in app_mounts:
                        
                            app_mounts[added_app[2]]=[]
                        
                        app_mounts[added_app[2]].append(app_name)
                
                arr_module_path[key_app]=os.path.dirname(sys.modules[module_app].__file__)

    for k_app,v_app in app_mounts.items():
        for t_app in v_app:
            if k_app!='/':
                app.mount(k_app, t_app) 
            elif k_app!='':
                app.merge(t_app)
    
    set_timezone()

    if error_reporting:
        from cuchulu.libraries.error_reporting import ErrorReportingPlugin
        
        app.install(ErrorReportingPlugin())
        
    if hasattr(config, 'plugins_app'):
        for p in config.plugins_app:
            app.install(p())

# Clean last slash

@app.hook('before_request')
def strip_path():
    request.environ['PATH_INFO'] = request.environ['PATH_INFO'].rstrip('/')
    
# Set error screen if not debug setted

if config.debug==False:
    @app.error(404)
    def error404(error):
        return 'Error: page not found'

debug(config.debug)

#Prepare app

application=app

# Load modules

try:
    
    prepare_app()
    
except:
    
    app.reset()
    
    @app.route('/')
    def catch_errors(all='/'):
        try:
            from pathlib import Path
            
            import time
            prepare_app()
            p=Path('app.py')
            p.touch()
            time.sleep(1)
        except:
            raise
            
        redirect(request.url)
    catch_errors=app.route('/<all:path>')(catch_errors)

# Prepare static routes

if config.yes_static==True:
    
    @app.route('/media/<filename:path>')
    def send_static(filename):
        mimetype=guess_type(workdir+'/themes/'+config.theme+'/media/'+filename)
        
        return static_file(filename, root=workdir+'/themes/'+config.theme+'/media/', mimetype=mimetype[0])
        
    @app.route('/mediafrom/<module>/<filename:path>')
    def send_static_module(module, filename):
        
        path_module=arr_module_path[module]+'/media/'
        
        file_path_module=path_module+filename
        
        path=workdir+'/themes/'+config.theme+'/media/'+module
        
        file_path=path+'/'+filename
        
        if os.path.isfile(file_path):
            mimetype=guess_type(path+'/'+filename)
            return static_file(filename, root=path, mimetype=mimetype[0])
            
        else:
            mimetype=guess_type(path_module+'/'+filename)
            return static_file(filename, root=path_module, mimetype=mimetype[0])
    

def error_handler_500(e):
    
    tpl_error="""
    %try:
        %from bottle import DEBUG, request
        <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
        <html>
            <head>
                <title>Error: {{e.status}}</title>
                <style type="text/css">
                  html {background-color: #e8eff0; font-family: sans;}
                  body {background-color: #fbfbfb; border: 1px solid #ddd;
                        padding: 15px; margin: 15px;}
                  pre {background-color: #e0f6fa; border: 1px solid #ddd; padding: 5px;}
                </style>
            </head>
            <body>
                <h1>Error: {{e.status}}</h1>
                <p>Sorry, the requested URL <tt>{{repr(request.url)}}</tt>
                   caused an error:</p>
                <pre>{{e.body}}</pre>
                %if DEBUG and e.exception:
                  <h2>Exception:</h2>
                  %try:
                    %exc = repr(e.exception)
                  %except:
                    %exc = '<unprintable %s object>' % type(e.exception).__name__
                  %end
                  <pre>{{exc}}</pre>
                %end
                %if DEBUG and e.traceback:
                  <h2>Traceback:</h2>
                  <pre>{{e.traceback}}</pre>
                %end
            </body>
        </html>
    %except ImportError:
        <b>ImportError:</b> Could not generate the error page. Please add bottle to
        the import path.
    %end
    """ 
    
    return template(tpl_error, e=e)

app.error(code=500, callback=error_handler_500)

def run_app(app):
    run(app=app, host=config.host, server=config.server_used, port=config.port, debug=config.debug, reloader=config.reloader)

