"""Application Flask principale pour Story App.

Ce fichier initialise l'application Flask, configure toutes les extensions
et enregistre les blueprints.
"""

import os
import logging
from logging.handlers import RotatingFileHandler
from flask import Flask, jsonify, send_from_directory
from flask_jwt_extended import JWTManager
from flask_cors import CORS
from flask_migrate import Migrate
from dotenv import load_dotenv

# Charger les variables d'environnement
load_dotenv()

# Import de la config
from config import Config

# Import du db depuis models.user (où il est défini)
from models.user import db

# Import des modèles (pour les migrations)
from models import (
    User,
    Story,
    StoryTurn,
    LoreBook,
    StoryLike,
    StoryFavorite
)


def create_app(config_class: type = Config) -> Flask:
    """Factory pour créer l'application Flask.
    
    Args:
        config_class: Classe de configuration à utiliser.
    
    Returns:
        Instance Flask configurée.
    """
    app = Flask(__name__)
    app.config.from_object(config_class)
    
    # Initialiser les extensions
    db.init_app(app)
    migrate = Migrate(app, db)
    jwt = JWTManager(app)
    CORS(app, origins=app.config['CORS_ORIGINS'])
    
    # Configuration du logging
    if not app.debug and not app.testing:
        if not os.path.exists('logs'):
            os.mkdir('logs')
        
        file_handler = RotatingFileHandler(
            'logs/story_app.log',
            maxBytes=10240000,
            backupCount=10
        )
        file_handler.setFormatter(logging.Formatter(
            '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
        ))
        file_handler.setLevel(logging.INFO)
        app.logger.addHandler(file_handler)
        app.logger.setLevel(logging.INFO)
        app.logger.info('Story App startup')
    
    # Handler d'erreurs JWT
    @jwt.expired_token_loader
    def expired_token_callback(jwt_header: dict, jwt_payload: dict) -> tuple:
        """Handler pour les tokens expirés.
        
        Args:
            jwt_header: Header du JWT.
            jwt_payload: Payload du JWT.
        
        Returns:
            Tuple (response, status_code).
        """
        return jsonify({
            'error': 'token_expired',
            'message': 'Le token a expiré'
        }), 401
    
    @jwt.invalid_token_loader
    def invalid_token_callback(error: str) -> tuple:
        """Handler pour les tokens invalides.
        
        Args:
            error: Message d'erreur.
        
        Returns:
            Tuple (response, status_code).
        """
        return jsonify({
            'error': 'invalid_token',
            'message': 'Le token est invalide'
        }), 401
    
    @jwt.unauthorized_loader
    def missing_token_callback(error: str) -> tuple:
        """Handler pour les tokens manquants.
        
        Args:
            error: Message d'erreur.
        
        Returns:
            Tuple (response, status_code).
        """
        return jsonify({
            'error': 'authorization_required',
            'message': 'Token d\'authentification manquant'
        }), 401
    
    # Handler d'erreurs global
    @app.errorhandler(404)
    def not_found_error(error: Exception) -> tuple:
        """Handler pour les erreurs 404.
        
        Args:
            error: Exception levée.
        
        Returns:
            Tuple (response, status_code).
        """
        return jsonify({
            'error': 'not_found',
            'message': 'Ressource non trouvée'
        }), 404
    
    @app.errorhandler(500)
    def internal_error(error: Exception) -> tuple:
        """Handler pour les erreurs 500.
        
        Args:
            error: Exception levée.
        
        Returns:
            Tuple (response, status_code).
        """
        db.session.rollback()
        app.logger.error(f'Erreur serveur: {error}')
        return jsonify({
            'error': 'internal_server_error',
            'message': 'Erreur interne du serveur'
        }), 500
    
    # Route de santé
    @app.route('/api/health')
    def health() -> dict:
        """Endpoint de santé pour vérifier que l'API fonctionne.
        
        Returns:
            Dictionnaire avec le statut de santé.
        """
        return jsonify({
            'status': 'ok',
            'environment': app.config['ENVIRONMENT'],
            'debug': app.config['DEBUG']
        })
    
    # Route pour l'interface de test
    @app.route('/')
    @app.route('/test')
    @app.route('/public/')
    def test_interface():
        """Serve l'interface de test HTML.
        
        Returns:
            Fichier HTML de l'interface de test.
        """
        return send_from_directory('public', 'index.html')
    
    @app.route('/admin')
    def admin_interface():
        """Serve l'interface d'administration.
        
        Returns:
            Fichier HTML du backoffice.
        """
        return send_from_directory('public', 'admin.html')
    
    # Import et enregistrement des blueprints
    from routes.auth import bp as auth_bp
    from routes.users import bp as users_bp
    from routes.stories import bp as stories_bp
    from routes.gameplay import bp as gameplay_bp
    from routes.admin import admin_bp
    
    app.register_blueprint(auth_bp, url_prefix='/api/auth')
    app.register_blueprint(users_bp, url_prefix='/api/users')
    app.register_blueprint(stories_bp, url_prefix='/api/stories')
    app.register_blueprint(gameplay_bp, url_prefix='/api/gameplay')
    app.register_blueprint(admin_bp)
    
    return app


# Créer l'application
app = create_app()


if __name__ == '__main__':
    """Point d'entrée pour le développement local."""
    app.run(debug=True, host='0.0.0.0', port=5000)

