# MIT License
# Copyright (c) 2025 Nible Tecnología en Desarrollo LTDA
# See LICENSE file for more details.

from flask import Flask,render_template, current_app, request
from jinja2 import FileSystemLoader, Environment
from core.utils.db import db
from core.models.listener import init_listeners, generic_executor
from core.routes.develop import container, field, permission, user, clazz, application, usergroup
from flask_migrate import Migrate
from config import Config
from flask_wtf.csrf import CSRFProtect
from flask_login import LoginManager
from core.models.develop.user import User
from project.models.production import clazzlist
from core.models.develop import requestlog, savedsession
from functools import wraps
import uuid

from sqlalchemy import event # <<< Importación necesaria para event.listen

import os

# Importa las Rutas de clases
from core.routes import routing
from project.routes import api
from project.routes import custom
from project.routes import webhook
from project.routes import frontend



# Define Login Manager 
login_manager = LoginManager()
@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

# Define la ruta raíz del proyecto
root_path = os.path.dirname(os.path.abspath(__file__))


# Inicializa el app
def create_app():
    app = Flask(__name__)
    app.config.from_object(Config)
    db.init_app(app)
    migrate = Migrate(app, db)
    csrf = CSRFProtect(app)


    ## Desactiva protección csfr para el webhook
    csrf.exempt(webhook.blueprintname)
    login_manager.init_app(app)

    # 1. Inicializar las referencias globales (antes de registrar el listener)
    init_listeners(app, db) 
    from project.models import events

    # 2. Registrar el listener de SQLAlchemy
    event.listen(db.session, 'after_commit', generic_executor)
    
    # Importa los Blueprint al app
    app.register_blueprint(user.blueprintname)
    app.register_blueprint(field.blueprintname)
    app.register_blueprint(container.blueprintname)
    app.register_blueprint(application.blueprintname)
    app.register_blueprint(clazz.blueprintname)
    app.register_blueprint(permission.blueprintname)
    app.register_blueprint(usergroup.blueprintname)
    app.register_blueprint(routing.blueprintname)
    app.register_blueprint(api.blueprintname)
    app.register_blueprint(custom.blueprintname)
    app.register_blueprint(webhook.blueprintname)
    app.register_blueprint(frontend.blueprintname)

    # --- Redefinición de rutas para las templates ---
    #app.config['TEMPLATES_AUTO_RELOAD'] = True
    root_path = os.path.dirname(os.path.abspath(__file__))
    CUSTOM_TEMPLATES_PATH = os.path.join(root_path, 'project', 'templates')
    CORE_TEMPLATES_PATH = os.path.join(root_path, 'core', 'templates')
    app.jinja_loader = FileSystemLoader([CUSTOM_TEMPLATES_PATH, CORE_TEMPLATES_PATH])
    # -------------------------------------------------
    
    # --- REGISTRO DEL MANEJADOR DE ERRORES 404 (DENTRO DE LA FUNCIÓN) ---
    @app.errorhandler(404)
    def page_not_found(e):
        # NOTA: Dentro de un errorhandler, 'e' contiene la descripción del error.
        app.logger.warning(f"404 Not Found: {e}, URL: {request.url}")

        # Retorna la plantilla '404.html' y el código de estado 404
        return render_template('404.html'), 404
    # -------------------------------------------------------------------

    @app.errorhandler(403)
    def forbidden(e):
        from flask import request
        from flask_login import current_user
        # Aquí puedes registrar el error si lo necesitas
        current_app.logger.warning(f"Acceso denegado (403): {current_user.id if current_user.is_authenticated else 'Invitado'} intentó acceder a {request.path}")
        
        # Renderiza la plantilla core/templates/403.html
        # La ruta de la plantilla es relativa a la carpeta 'templates' registrada en tu aplicación.
        return render_template('403.html'), 403
    
    return app