import json
import os
from flask import Flask, render_template
from .extensions import db, migrate


def create_app(config=None):
    """
    Application factory — complete implementation (Story 1.5).
    Registers all blueprint stubs, WAL mode (via extensions.py Engine event),
    config classes, and error handlers.
    Story 2.1 adds full template-based error pages.
    """
    app = Flask(__name__)

    # Load config from config.py based on APP_ENV / FLASK_ENV
    env = os.environ.get('APP_ENV', os.environ.get('FLASK_ENV', 'development'))
    from config import config as config_map, get_database_url
    app.config.from_object(config_map.get(env, config_map['default']))
    app.config['SQLALCHEMY_DATABASE_URI'] = get_database_url()

    # Test / override config (dict passed directly — used by conftest.py)
    if config:
        app.config.update(config)

    # Initialize extensions (WAL mode listener already registered in extensions.py)
    db.init_app(app)
    migrate.init_app(app, db)

    # Register ORM models with SQLAlchemy metadata so flask db migrate detects all tables.
    # Use __import__ to avoid rebinding the local 'app' variable (Flask instance).
    __import__('app.models')

    # Register blueprint stubs
    from app.blueprints.dashboard import dashboard_bp
    from app.blueprints.transactions import transactions_bp
    from app.blueprints.budgets import budgets_bp
    from app.blueprints.settings import settings_bp
    from app.blueprints.bills import bills_bp
    from app.blueprints.paydown import paydown_bp
    from app.blueprints.import_pdf import import_pdf_bp
    from app.blueprints.analytics import analytics_bp
    from app.blueprints.api import api_bp

    app.register_blueprint(dashboard_bp)
    app.register_blueprint(transactions_bp, url_prefix='/transactions')
    app.register_blueprint(budgets_bp, url_prefix='/budgets')
    app.register_blueprint(settings_bp, url_prefix='/settings')
    app.register_blueprint(bills_bp, url_prefix='/bills')
    app.register_blueprint(paydown_bp, url_prefix='/paydown')
    app.register_blueprint(import_pdf_bp, url_prefix='/import')
    app.register_blueprint(analytics_bp, url_prefix='/analytics')
    app.register_blueprint(api_bp, url_prefix='/api')

    # Custom Jinja2 filters
    @app.template_filter('from_json')
    def from_json_filter(value):
        if not value:
            return []
        try:
            return json.loads(value)
        except (json.JSONDecodeError, TypeError):
            return []

    # Template-based error handlers (Story 2.1)
    @app.errorhandler(404)
    def not_found(e):
        return render_template('errors/404.html'), 404

    @app.errorhandler(500)
    def server_error(e):
        return render_template('errors/500.html'), 500

    return app
