from flask import Flask
from flask_bootstrap5 import Bootstrap
from flask_login import LoginManager
from flask_wtf.csrf import CSRFProtect
from flask_mail import Mail
from functions.database import get_db_connection, Usuario
from functions.rbac import init_rbac
from functions.template_helpers import permission_context_processor, init_template_filters, safe_render_helper
from sqlalchemy.orm import joinedload
import os
import secrets
from dotenv import load_dotenv
import sys
import logging
from logging.handlers import RotatingFileHandler
import time

# Importar blueprints
from controllers.auth_controller import auth_bp
from controllers.home_controller import home_bp
from controllers.militante_controller import militante_bp
from controllers.pagamento_controller import pagamento_bp
from controllers.cota_controller import cota_bp
from controllers.usuario_controller import usuario_bp
from controllers.material_controller import material_bp
from routes.admin import admin_bp

# Import cache service
from services.cache_service import cache_service

load_dotenv()

def setup_logging(app):
    """Configure logging for the application"""
    if not app.debug and not app.testing:
        # Create logs directory if it doesn't exist
        if not os.path.exists('logs'):
            os.mkdir('logs')
        
        # File handler for general logs
        file_handler = RotatingFileHandler('logs/controles.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)
        
        # File handler for cache logs
        cache_handler = RotatingFileHandler('logs/cache.log', maxBytes=10240000, backupCount=5)
        cache_handler.setFormatter(logging.Formatter(
            '%(asctime)s %(levelname)s: %(message)s'
        ))
        cache_handler.setLevel(logging.DEBUG)
        
        # Create cache logger
        cache_logger = logging.getLogger('services.cache_service')
        cache_logger.addHandler(cache_handler)
        cache_logger.setLevel(logging.DEBUG)
        
        app.logger.setLevel(logging.INFO)
        app.logger.info('Controles startup')

def create_app():
    """Cria e configura a aplicação Flask"""
    app = Flask(__name__)
    app.secret_key = os.getenv('SECRET_KEY', secrets.token_hex(16))
    
    # Setup logging
    setup_logging(app)
    
    # Configurar Bootstrap
    bootstrap = Bootstrap(app)

    # Configurar CSRF Protection (desabilitado temporariamente)
    # csrf = CSRFProtect()
    # csrf.init_app(app)
    
    # Configurar cabeçalhos CSRF personalizados
    app.config['WTF_CSRF_CHECK_DEFAULT'] = False
    app.config['WTF_CSRF_HEADERS'] = ['X-CSRFToken']
    
    # Configurar Flask-Login
    login_manager = LoginManager()
    login_manager.init_app(app)
    login_manager.login_view = 'auth.login'

    # Configurar context processors e template helpers
    app.context_processor(permission_context_processor)
    app.context_processor(safe_render_helper)
    
    # Inicializar filtros de template personalizados
    init_template_filters(app)
    
    # Adicionar filtros Jinja2
    @app.template_filter('bitwise_and')
    def bitwise_and(value1, value2):
        """Filtro para operação bit a bit AND"""
        return value1 & value2

    @login_manager.user_loader
    def load_user(user_id):
        """Carrega o usuário pelo ID"""
        db = get_db_connection()
        try:
            # Carregar o usuário com suas roles
            user = db.query(Usuario).options(
                joinedload(Usuario.roles)
            ).get(user_id)
            return user
        finally:
            db.close()

    # Configurar Flask-Mail
    app.config['MAIL_SERVER'] = os.getenv('MAIL_SERVER', 'smtp.gmail.com')
    app.config['MAIL_PORT'] = int(os.getenv('MAIL_PORT', 587))
    app.config['MAIL_USE_TLS'] = os.getenv('MAIL_USE_TLS', 'True').lower() == 'true'
    app.config['MAIL_USERNAME'] = os.getenv('MAIL_USERNAME')
    app.config['MAIL_PASSWORD'] = os.getenv('MAIL_PASSWORD')
    app.config['MAIL_DEFAULT_SENDER'] = os.getenv('MAIL_DEFAULT_SENDER')

    mail = Mail(app)

    # Initialize Redis cache
    try:
        redis_url = os.getenv('REDIS_URL', 'redis://localhost:6379/0')
        app.logger.info(f"Initializing Redis cache with URL: {redis_url}")
        
        # Test cache connection with retry
        max_retries = 5
        retry_delay = 2
        
        for attempt in range(max_retries):
            try:
                if cache_service._is_connected():
                    app.logger.info("Redis cache connection successful")
                    break
                else:
                    app.logger.warning(f"Redis cache connection attempt {attempt + 1} failed")
                    if attempt < max_retries - 1:
                        time.sleep(retry_delay)
                        retry_delay *= 2  # Exponential backoff
            except Exception as e:
                app.logger.warning(f"Redis cache connection attempt {attempt + 1} failed: {e}")
                if attempt < max_retries - 1:
                    time.sleep(retry_delay)
                    retry_delay *= 2
        else:
            app.logger.warning("Redis cache connection failed after all retries - continuing without cache")
    except Exception as e:
        app.logger.error(f"Error initializing Redis cache: {e}")
        app.logger.info("Application will continue without Redis cache")

    # Registrar blueprints
    app.register_blueprint(auth_bp)
    app.register_blueprint(home_bp)
    app.register_blueprint(militante_bp)
    app.register_blueprint(pagamento_bp)
    app.register_blueprint(cota_bp)
    app.register_blueprint(usuario_bp)
    app.register_blueprint(material_bp)
    app.register_blueprint(admin_bp)

    return app

def init_system():
    """Inicializa o sistema"""
    print("Inicializando sistema...")
    
    # Inicializar RBAC
    print("Inicializando RBAC...")
    init_rbac()
    
    # Criar usuário admin se não existir
    from create_admin import create_admin_user
    print("Criando usuário admin...")
    create_admin_user()
    
    print("Sistema inicializado com sucesso!")

def main():
    """Função principal"""
    # Criar a aplicação
    app = create_app()
    return app

# Criar a aplicação usando a função main
app = main()

if __name__ == '__main__':
    # Verificar se é para inicializar o sistema
    if '--init' in sys.argv:
        init_system()
    else:
        app.run(
            host='0.0.0.0',
            port=5000,
            debug=os.getenv('FLASK_ENV') == 'development'
        )
