"""
BeanFlows - Application factory and entry point.
"""
import os
from pathlib import Path

from quart import Quart, g, session

from .analytics import close_analytics_db, open_analytics_db
from .core import close_db, config, get_csrf_token, init_db, setup_request_id


def create_app() -> Quart:
    """Create and configure the Quart application."""

    # Get package directory for templates
    pkg_dir = Path(__file__).parent

    app = Quart(
        __name__,
        template_folder=str(pkg_dir / "templates"),
        static_folder=str(pkg_dir / "static"),
    )

    app.secret_key = config.SECRET_KEY

    # Session config
    app.config["SESSION_COOKIE_SECURE"] = not config.DEBUG
    app.config["SESSION_COOKIE_HTTPONLY"] = True
    app.config["SESSION_COOKIE_SAMESITE"] = "Lax"
    app.config["PERMANENT_SESSION_LIFETIME"] = 60 * 60 * 24 * config.SESSION_LIFETIME_DAYS

    # Database lifecycle
    @app.before_serving
    async def startup():
        await init_db()
        if os.getenv("SERVING_DUCKDB_PATH"):
            open_analytics_db()

    @app.after_serving
    async def shutdown():
        close_analytics_db()
        await close_db()

    # Security headers
    @app.after_request
    async def add_security_headers(response):
        response.headers["X-Content-Type-Options"] = "nosniff"
        response.headers["X-Frame-Options"] = "DENY"
        response.headers["X-XSS-Protection"] = "1; mode=block"
        if not config.DEBUG:
            response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
        return response

    # Load current user + subscription + roles before each request
    @app.before_request
    async def load_user():
        g.user = None
        g.subscription = None
        user_id = session.get("user_id")
        if user_id:
            from .core import fetch_one as _fetch_one
            row = await _fetch_one(
                """SELECT u.*,
                          bc.provider_customer_id,
                          (SELECT GROUP_CONCAT(role) FROM user_roles WHERE user_id = u.id) AS roles_csv,
                          s.id AS sub_id, s.plan, s.status AS sub_status,
                          s.provider_subscription_id, s.current_period_end
                   FROM users u
                   LEFT JOIN billing_customers bc ON bc.user_id = u.id
                   LEFT JOIN subscriptions s ON s.id = (
                       SELECT id FROM subscriptions
                       WHERE user_id = u.id
                       ORDER BY created_at DESC LIMIT 1
                   )
                   WHERE u.id = ? AND u.deleted_at IS NULL""",
                (user_id,),
            )
            if row:
                g.user = dict(row)
                g.user["roles"] = row["roles_csv"].split(",") if row["roles_csv"] else []
                if row["sub_id"]:
                    g.subscription = {
                        "id": row["sub_id"], "plan": row["plan"],
                        "status": row["sub_status"],
                        "provider_subscription_id": row["provider_subscription_id"],
                        "current_period_end": row["current_period_end"],
                    }

    # Template context globals
    @app.context_processor
    def inject_globals():
        from datetime import datetime
        return {
            "config": config,
            "user": g.get("user"),
            "subscription": g.get("subscription"),
            "is_admin": "admin" in (g.get("user") or {}).get("roles", []),
            "now": datetime.utcnow(),
            "csrf_token": get_csrf_token,
            "ab_variant": getattr(g, "ab_variant", None),
            "ab_tag": getattr(g, "ab_tag", None),
        }

    # Health check
    @app.route("/health")
    async def health():
        from .analytics import _db_path as serving_db_path, fetch_analytics
        from .core import fetch_one
        result = {"status": "healthy", "sqlite": "ok", "duckdb": "ok"}
        try:
            await fetch_one("SELECT 1")
        except Exception as e:
            result["sqlite"] = str(e)
            result["status"] = "unhealthy"
        if serving_db_path:
            try:
                await fetch_analytics("SELECT 1")
            except Exception as e:
                result["duckdb"] = str(e)
                result["status"] = "unhealthy"
        else:
            result["duckdb"] = "not configured"
        status_code = 200 if result["status"] == "healthy" else 500
        return result, status_code

    # Register blueprints
    from .admin.cms_routes import bp as cms_bp
    from .admin.routes import bp as admin_bp
    from .api.routes import bp as api_bp
    from .auth.routes import bp as auth_bp
    from .billing.routes import bp as billing_bp
    from .content.routes import bp as content_bp
    from .dashboard.routes import bp as dashboard_bp
    from .public.routes import bp as public_bp

    app.register_blueprint(public_bp)
    app.register_blueprint(auth_bp)
    app.register_blueprint(dashboard_bp)
    app.register_blueprint(billing_bp)
    app.register_blueprint(api_bp, url_prefix="/api/v1")
    app.register_blueprint(content_bp)
    app.register_blueprint(cms_bp)
    app.register_blueprint(admin_bp)

    # Request ID tracking
    setup_request_id(app)

    return app


app = create_app()


if __name__ == "__main__":
    app.run(debug=config.DEBUG, port=5001)
