"""Application factory for the Flask platform runtime."""

from __future__ import annotations

import os
from collections.abc import Callable
from datetime import datetime, timezone
from typing import Any

from flask import Flask, jsonify, request
from sqlalchemy import text

from config.base import Config
from config.control_plane import get_control_plane_engine
from config.db import init_db_app
from bridge_platform.gateway.api_gateway import APIGateway
from bridge_platform.gateway.platform_api import platform_api


AppRegistrar = Callable[[Flask], None]


def create_app(test_config: dict[str, Any] | None = None) -> Flask:
    """Build the complete platform application and record startup diagnostics."""
    app = Flask(__name__)
    app.config.from_object(Config)
    app.config.update(
        MAX_CONTENT_LENGTH=int(os.getenv("MAX_UPLOAD_MB", "20")) * 1024 * 1024,
        WP_INVOICES_UPLOAD_DIR=os.getenv(
            "WP_INVOICES_UPLOAD_DIR",
            "/var/www/html/flask_server/data/wp_invoices/uploads",
        ),
        WP_INVOICES_DEFAULT_DPI=int(os.getenv("WP_INVOICES_DEFAULT_DPI", "220")),
        REQUIRED_APPS=("wp_invoices", "leave_form_app"),
        CHECK_CONTROL_DB_READINESS=True,
        REGISTER_BOOTSTRAP_SITES=True,
    )
    if test_config:
        app.config.update(test_config)

    init_db_app(app)
    app.extensions["startup_components"] = {}
    app.register_blueprint(platform_api)
    _record_component(app, "platform_api", True)

    _register_business_apps(app)
    _register_runtime_routes(app)
    return app


def _register_business_apps(app: Flask) -> None:
    registrations: tuple[tuple[str, Callable[[], AppRegistrar]], ...] = (
        (
            "qr_service",
            lambda: _import_registrar("apps.qr_service", "register_qr_service"),
        ),
        (
            "wp_invoices",
            lambda: _import_registrar("apps.wp_invoices", "register_blueprints"),
        ),
        (
            "leave_form_app",
            lambda: _import_registrar("apps.leave_form_app", "register_leave_form_app"),
        ),
    )
    for app_id, registrar_loader in registrations:
        try:
            registrar_loader()(app)
        except Exception as exc:
            _record_component(app, app_id, False, str(exc))
            app.logger.exception("Required app registration failed: %s", app_id)
        else:
            _record_component(app, app_id, True)


def _import_registrar(module_path: str, attribute: str) -> AppRegistrar:
    from importlib import import_module

    module = import_module(module_path)
    registrar = getattr(module, attribute)
    return registrar


def _register_runtime_routes(app: Flask) -> None:
    gateway = APIGateway()

    @app.route("/api/v1/<app_name>/<path:action>", methods=["GET", "POST"])
    def handle_gateway_request(app_name: str, action: str):
        return gateway.handle(request, app_name, action)

    @app.get("/health")
    def health():
        """Liveness: the WSGI process can serve requests."""
        return {
            "status": "ok",
            "service": "flask_server",
            "check": "liveness",
        }

    @app.get("/ready")
    def ready():
        """Readiness: required apps and infrastructure are available."""
        components = dict(app.extensions.get("startup_components") or {})
        required_apps = tuple(app.config.get("REQUIRED_APPS") or ())
        missing_apps = [
            app_id
            for app_id in required_apps
            if not components.get(app_id, {}).get("ready", False)
        ]

        database = _control_database_status(app)
        ready_state = not missing_apps and database["ready"]
        payload = {
            "status": "ok" if ready_state else "not_ready",
            "service": "flask_server",
            "check": "readiness",
            "checked_at": datetime.now(timezone.utc).isoformat(),
            "components": components,
            "control_database": database,
        }
        return jsonify(payload), 200 if ready_state else 503


def _control_database_status(app: Flask) -> dict[str, Any]:
    if not app.config.get("CHECK_CONTROL_DB_READINESS", True):
        return {"ready": True, "check": "disabled"}
    try:
        with get_control_plane_engine().connect() as connection:
            connection.execute(text("SELECT 1"))
    except Exception as exc:
        return {
            "ready": False,
            "error": type(exc).__name__,
        }
    return {"ready": True}


def _record_component(
    app: Flask,
    component: str,
    ready: bool,
    error: str | None = None,
) -> None:
    state: dict[str, Any] = {"ready": ready}
    if error:
        state["error"] = error
    app.extensions["startup_components"][component] = state
