"""TieMeasureFlow Client - Flask Entry Point."""
import json
import os
from urllib.parse import urlparse

from flask import Flask, redirect, url_for, session, request
from flask_babel import Babel
from flask_wtf.csrf import CSRFProtect
from markupsafe import Markup
from werkzeug.middleware.proxy_fix import ProxyFix

from config import Config


def get_locale():
    """Get user's preferred language from session or Accept-Language header."""
    # 1. User preference in session
    if "language" in session:
        return session["language"]
    # 2. Browser Accept-Language
    return request.accept_languages.best_match(
        Config.LANGUAGES.keys(), default="it"
    )


def create_app() -> Flask:
    """Application factory."""
    app = Flask(__name__)
    app.config.from_object(Config)

    # Trust one reverse-proxy hop (Nginx in dev, Traefik in prod) so that
    # request.remote_addr returns the real tablet IP rather than the proxy IP.
    # The APIClient forwards that IP to FastAPI for accurate rate limiting.
    app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)

    # Initialize CSRF protection
    csrf = CSRFProtect(app)

    # Initialize Flask-Babel
    Babel(app, locale_selector=get_locale)

    # Register blueprints
    from blueprints.auth import auth_bp
    from blueprints.measure import measure_bp
    from blueprints.maker import maker_bp
    from blueprints.statistics import statistics_bp
    from blueprints.admin import admin_bp

    app.register_blueprint(auth_bp)
    app.register_blueprint(measure_bp, url_prefix="/measure")
    app.register_blueprint(maker_bp, url_prefix="/maker")
    app.register_blueprint(statistics_bp, url_prefix="/statistics")
    app.register_blueprint(admin_bp, url_prefix="/admin")

    @app.route("/")
    def index():
        """Root redirect to login or dashboard based on session."""
        if "user" in session:
            return redirect(url_for("measure.select_recipe"))
        return redirect(url_for("auth.login"))

    @app.route("/set-language/<lang>")
    def set_language(lang):
        """Set user's preferred language and store in session."""
        if lang in Config.LANGUAGES:
            session["language"] = lang
        # Only follow the referrer if it points back to this host
        # (prevents open redirect via a forged Referer header).
        referrer = request.referrer
        if referrer:
            parsed = urlparse(referrer)
            if parsed.netloc and parsed.netloc != request.host:
                referrer = None
        return redirect(referrer or url_for("auth.login"))

    @app.template_filter("tojson_attr")
    def tojson_attr_filter(value):
        """JSON encode safe for HTML attributes (x-data, etc.).

        Unlike |tojson, this escapes double quotes to &#34; so the output
        can be safely embedded inside double-quoted HTML attributes.
        The browser decodes the entities before Alpine.js evaluates them.
        """
        rv = json.dumps(value, ensure_ascii=False)
        rv = (
            rv.replace("&", "\\u0026")
            .replace("<", "\\u003c")
            .replace(">", "\\u003e")
            .replace("'", "\\u0027")
            .replace('"', "&#34;")
        )
        return Markup(rv)

    @app.context_processor
    def inject_globals():
        """Inject global variables into all templates."""
        return {
            "current_user": session.get("user"),
            "current_theme": session.get("theme", "light"),
            "current_language": get_locale(),
            "languages": Config.LANGUAGES,
            "company_logo": session.get("company_logo"),
            "auto_logout_minutes": session.get("auto_logout_minutes"),
        }

    return app


if __name__ == "__main__":
    app = create_app()
    app.run(
        host=os.getenv("CLIENT_HOST", "0.0.0.0"),
        port=int(os.getenv("CLIENT_PORT", "5000")),
        debug=True,
    )
