"""
GMAO Collège - Application Flask Modulaire
Structure par domaine métier
"""
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_migrate import Migrate
from flask_wtf.csrf import CSRFProtect
from datetime import timedelta
import os
import json
import re
from jinja2 import ChoiceLoader, FileSystemLoader, PrefixLoader
from markupsafe import Markup, escape

# Extensions (définies dans extensions.py)
from .extensions import db, login_manager, migrate, csrf

# Import all models to register them in SQLAlchemy metadata
from .core import models


def create_app(config_name='default'):
    """Factory pour créer l'application Flask."""
    # Chemin absolu vers le répertoire app_new
    app_dir = os.path.dirname(os.path.abspath(__file__))
    
    # Chemins absolus pour templates et instance
    template_dir = os.path.join(app_dir, 'templates')
    instance_dir = os.path.join(app_dir, 'instance')
    
    # Créer le dossier instance s'il n'existe pas
    os.makedirs(instance_dir, exist_ok=True)
    
    # Charger les variables d'environnement depuis .env AVANT la config
    from dotenv import load_dotenv
    load_dotenv()
    
    app = Flask(__name__,
                instance_path=instance_dir,
                instance_relative_config=True,
                template_folder=template_dir,
                static_folder=os.path.join(app_dir, 'static'))

    # Les modules historiques contiennent plusieurs templates portant le même
    # nom (notamment ``detail.html``). Ce préfixe garantit que la fiche
    # intervention charge toujours le template du bon module.
    app.jinja_loader = ChoiceLoader([
        app.jinja_loader,
        PrefixLoader({
            'interventions_module': FileSystemLoader(
                os.path.join(app_dir, 'interventions', 'templates')
            ),
        }),
    ])
    
    # Tolerer les slashs finaux dans les URLs
    app.url_map.strict_slashes = False
    
    # Configuration
    from .config import config as config_dict
    config_class = config_dict[config_name]
    app.config.from_object(config_class)
    config_class.init_app(app)

    # Affiché notamment dans le setup wizard afin d'identifier sans ambiguïté
    # le code réellement exécuté par un conteneur, même avant installation.
    from .core.build_info import get_build_commit
    from .version import get_version
    app.config['GIT_COMMIT'] = get_build_commit()
    app.config['GMAO_VERSION'] = get_version()
    app.context_processor(lambda: {
        'build_commit': app.config['GIT_COMMIT'],
        'gmao_version': app.config['GMAO_VERSION'],
    })
    
    # Initialisation des extensions
    db.init_app(app)
    login_manager.init_app(app)
    migrate.init_app(app, db)
    csrf.init_app(app)

    from .core.authorization import enforce_route_permission, has_permission
    app.before_request(enforce_route_permission)
    app.jinja_env.globals["has_permission"] = has_permission
    from .core.audit import record_mutation
    app.after_request(record_mutation)
    
    # Configuration du login manager
    login_manager.login_view = 'auth.login'
    login_manager.login_message = 'Veuillez vous connecter pour accéder à cette page.'
    login_manager.login_message_category = 'warning'
    
    # Import des modèles AVANT les blueprints
    from .core import models as core_models
    from .pronote import models as pronote_models
    from .ent import models as ent_models
    from .outlook import models as outlook_models
    from .yeastar import models as yeastar_models
    
    # Enregistrement des blueprints
    from .core.routes import auth_bp, admin_bp, dashboard_bp, setup_wizard_bp
    
    app.register_blueprint(auth_bp, url_prefix='/auth')
    app.register_blueprint(admin_bp, url_prefix='/admin')
    app.register_blueprint(dashboard_bp, url_prefix='/')
    app.register_blueprint(setup_wizard_bp, url_prefix='/setup-wizard')
    
    # Blueprints des modules métier
    from .equipments.routes import (
        equipments_bp, meters_bp, documents_bp, restrictions_bp, scheduled_bp
    )
    from .equipments.buildings import buildings_bp
    from .equipments.zones import zones_bp
    from .equipments.rooms import rooms_bp
    app.register_blueprint(equipments_bp, url_prefix='/equipments')
    app.register_blueprint(buildings_bp, url_prefix='/equipments/buildings')
    app.register_blueprint(zones_bp, url_prefix='/equipments/zones')
    app.register_blueprint(rooms_bp, url_prefix='/equipments/rooms')
    app.register_blueprint(meters_bp, url_prefix='/equipments')
    app.register_blueprint(documents_bp, url_prefix='/equipments')
    app.register_blueprint(restrictions_bp, url_prefix='/equipments')
    app.register_blueprint(scheduled_bp, url_prefix='/equipments')
    
    from .interventions.routes import interventions_bp, interventions_planning_bp
    app.register_blueprint(interventions_bp, url_prefix='/interventions')
    app.register_blueprint(interventions_planning_bp, url_prefix='/interventions')
    
    from .planning.routes import planning_bp
    app.register_blueprint(planning_bp, url_prefix='/planning')
    
    from .companies.routes import companies_bp
    app.register_blueprint(companies_bp, url_prefix='/companies')
    
    from .lots.routes import lots_bp
    app.register_blueprint(lots_bp, url_prefix='/lots')
    
    from .training.routes import training_bp
    app.register_blueprint(training_bp, url_prefix='/training')
    
    from .meters.routes import meters_bp
    app.register_blueprint(meters_bp, url_prefix='/meters')
    
    from .parts.routes import parts_bp
    app.register_blueprint(parts_bp, url_prefix='/parts')

    from .c4 import c4_bp
    app.register_blueprint(c4_bp, url_prefix='/c4')

    # Matériel et produits d'entretien (stock, FEFO, distributions, prévisions)
    from .cleaning import cleaning_bp
    app.register_blueprint(cleaning_bp)
    
    from .services_module.routes import services_bp
    app.register_blueprint(services_bp, url_prefix='/services')
    
    from .room_types.routes import room_types_bp
    app.register_blueprint(room_types_bp, url_prefix='/room-types')

    from .room_profiles.routes import room_profiles_bp
    app.register_blueprint(room_profiles_bp, url_prefix='/room-profiles')
    
    from .documents.routes import documents_bp
    app.register_blueprint(documents_bp, url_prefix='/documents')
    
    from .gmao_config.routes import gmao_config_bp
    app.register_blueprint(gmao_config_bp, url_prefix='/gmao-config')

    from .configuration.routes import configuration_bp
    app.register_blueprint(configuration_bp, url_prefix='/configuration')
    
    from .wizard.routes import wizard_bp
    app.register_blueprint(wizard_bp)

    from .housing import housing_bp
    app.register_blueprint(housing_bp, url_prefix='/housing')
    from .prevention import prevention_bp
    app.register_blueprint(prevention_bp, url_prefix='/prevention')
    from .works import works_bp
    app.register_blueprint(works_bp, url_prefix='/interventions/work')
    
    # Blueprints des intégrations
    from .pronote.routes import pronote_bp
    app.register_blueprint(pronote_bp, url_prefix='/pronote')
    
    from .ent.routes import ent_bp
    app.register_blueprint(ent_bp, url_prefix='/ent')
    
    from .outlook.routes import outlook_bp, outlook_auth_bp, outlook_sync_bp, outlook_dashboard_bp
    app.register_blueprint(outlook_bp, url_prefix='/outlook')
    app.register_blueprint(outlook_auth_bp, url_prefix='/outlook')
    app.register_blueprint(outlook_sync_bp, url_prefix='/outlook')
    app.register_blueprint(outlook_dashboard_bp, url_prefix='/outlook')

    
    from .yeastar.routes import yeastar_bp
    app.register_blueprint(yeastar_bp, url_prefix='/yeastar')
    
    from .chatbot.routes import chatbot_bp
    app.register_blueprint(chatbot_bp, url_prefix='/chatbot')
    
    # Blueprint status systeme
    from .status.routes import status_bp
    app.register_blueprint(status_bp)
    
    from .health import health_bp
    app.register_blueprint(health_bp)
    
    # Logs centralises des watchdogs
    from .logs.routes import logs_bp
    app.register_blueprint(logs_bp)
    
    # API REST v1
    from .api.routes import api_bp
    app.register_blueprint(api_bp)
    csrf.exempt(api_bp)
    
    # Notifications temps reel
    from .notifications.routes import notifications_bp
    app.register_blueprint(notifications_bp)
    
    # Exports PDF/CSV
    from .exports.routes import exports_bp
    app.register_blueprint(exports_bp)
    
    # Messagerie unifiee
    from .messagerie.routes import messagerie_bp
    app.register_blueprint(messagerie_bp)
    
    # Contrats d'entreprise
    from .contracts.models import Contract, ContractVisit
    from .contracts.routes import contracts_bp
    app.register_blueprint(contracts_bp)
    
    # Configuration IA (OpenRouter)
    from .ai_config.routes import ai_config_bp
    app.register_blueprint(ai_config_bp)
    
    # Contraintes de zone
    from .constraints.routes import constraints_bp
    app.register_blueprint(constraints_bp)
    
    # Planificateur automatique
    from .scheduler.routes import scheduler_bp
    app.register_blueprint(scheduler_bp)
    
    # Filtres Jinja2 pour les templates
    from .utils import format_status, status_badge_class, priority_badge_class, bootstrap_color_to_hex, bootstrap_text_color, format_datetime, local_datetime
    
    app.jinja_env.filters["date_fmt"] = lambda value: value.strftime("%d/%m/%Y") if value else ""
    app.jinja_env.filters["datetime_fmt"] = format_datetime
    app.jinja_env.filters["local_datetime"] = local_datetime
    app.jinja_env.filters["format_status"] = format_status
    app.jinja_env.filters["status_badge"] = status_badge_class
    app.jinja_env.filters["priority_badge"] = priority_badge_class
    app.jinja_env.filters["from_json"] = lambda value: json.loads(value) if value else []
    app.jinja_env.filters["hex_color"] = bootstrap_color_to_hex
    app.jinja_env.filters["text_color"] = bootstrap_text_color
    # Le détail des équipements conserve les retours à la ligne des
    # descriptions via ce filtre partagé par les templates du projet.
    def nl2br(value):
        if value is None:
            return ""
        return Markup("<br>\n").join(escape(line) for line in str(value).splitlines())

    app.jinja_env.filters["nl2br"] = nl2br
    app.jinja_env.filters["slugify"] = lambda value: re.sub(r'[^a-z0-9]+', '-', str(value or '').lower()).strip('-')
    app.jinja_env.globals["timedelta"] = timedelta
    
    # Gestionnaires d'erreurs personnalisées
    @app.errorhandler(404)
    def not_found_error(e):
        return render_template('errors/error.html',
                               error_code='404',
                               error_title='Page non trouvée',
                               error_message='La page demandée n’existe pas ou a été déplacée.'), 404

    @app.errorhandler(500)
    def internal_error(e):
        try:
            db.session.rollback()
        except Exception:
            pass
        return render_template('errors/error.html',
                               error_code='500',
                               error_title='Erreur serveur',
                               error_message='Une erreur est survenue. Elle a été signalée automatiquement.'), 500

    @app.errorhandler(403)
    def forbidden_error(e):
        return render_template('errors/error.html',
                               error_code='403',
                               error_title='Accès refusé',
                               error_message='Vous n’avez pas les droits nécessaires pour accéder à cette page.'), 403

    return app


# User loader pour Flask-Login
@login_manager.user_loader
def load_user(user_id):
    """Charge un utilisateur par son ID."""
    from .core.models.user import User
    return User.query.get(int(user_id))
