"""
initializer.py

Purpose:
  Build and configure the Flask app, applying configuration, registering
  teardown hooks, assets, and all blueprints. This keeps `app.py` minimal so it
  only imports the created app and optionally runs a dev server.

Exports:
  - create_app() -> Flask
"""

import os
from flask import Flask
from .paths import ROOT_DIR, STATIC_PATH
from .config import apply_config
from .db import register_teardown
from .assets import register_assets
from .views import bp as views_bp
from .cameras_api import bp as cameras_api_bp
from .gallery import bp as gallery_bp
from .map_routes import bp as map_bp
from .admin_routes import bp as admin_bp
from .media_routes import bp as media_bp
from .security_enhancements import security_headers_middleware


def create_app() -> Flask:
    app = Flask(
        __name__,
        template_folder=os.path.join(ROOT_DIR, 'templates'),
        static_folder=STATIC_PATH,
        static_url_path='/static'
    )

    apply_config(app)
    register_teardown(app)
    register_assets(app)

    # Enhanced security headers using security_enhancements module
    @app.after_request
    def add_security_headers(resp):
        return security_headers_middleware(resp)

    # Mount blueprints (no prefixes to preserve existing URLs)
    app.register_blueprint(views_bp)
    app.register_blueprint(cameras_api_bp)
    app.register_blueprint(gallery_bp)
    app.register_blueprint(map_bp)
    app.register_blueprint(admin_bp)
    app.register_blueprint(media_bp)

    # Minimal CSRF token support for JSON and forms
    # Token is stored in session and mirrored in a meta tag on HTML pages
    import secrets
    from flask import session, request, abort, g

    @app.before_request
    def ensure_csrf_token():
        # Create token if not present
        if 'csrf_token' not in session:
            session['csrf_token'] = secrets.token_urlsafe(32)
        # Per-request CSP nonce
        g.csp_nonce = secrets.token_urlsafe(16)

    @app.context_processor
    def inject_csrf_token():
        return { 'CSRF_TOKEN': session.get('csrf_token', ''), 'CSP_NONCE': getattr(g, 'csp_nonce', '') }

    # Enforce CSRF on state-changing requests
    @app.before_request
    def csrf_protect():
        if request.method in ('POST', 'PUT', 'PATCH', 'DELETE'):
            # Allow login to work before token is set, but encourage adding token later
            if request.endpoint in {'views.login_root', 'views.login_login', 'views.login_post_alias'}:
                return
            token = request.headers.get('X-CSRF-Token') or request.form.get('csrf_token') or request.args.get('csrf_token')
            if not token or token != session.get('csrf_token'):
                abort(403)

    return app


