"""Flask application factory."""
from __future__ import annotations

import os
from pathlib import Path

from flask import Flask, jsonify, send_from_directory

from backend.app.api import auth_bp, engagements_bp, simulations_bp, users_bp
from backend.app.cli import register_cli
from backend.app.config import Config, TestConfig
from backend.app.errors import register_error_handlers
from backend.app.extensions import db, migrate


def create_app(config_object: object | None = None) -> Flask:
    """Application factory.

    `config_object` is an *instance* (not a class) of Config or a subclass.
    If None, picks TestConfig when MIMIC_TESTING=1, otherwise Config.
    """
    static_folder = str(Path(__file__).parent / "static")
    app = Flask(__name__, static_folder=static_folder, static_url_path="/static")

    if config_object is None:
        config_object = TestConfig() if os.environ.get("MIMIC_TESTING") == "1" else Config()
    app.config.from_object(config_object)

    db.init_app(app)
    migrations_dir = str(Path(__file__).parent.parent / "migrations")
    migrate.init_app(app, db, directory=migrations_dir)

    # Ensure models are imported so Alembic/metadata see them.
    from backend.app import models  # noqa: F401

    app.register_blueprint(auth_bp)
    app.register_blueprint(users_bp)
    app.register_blueprint(engagements_bp)
    app.register_blueprint(simulations_bp)

    from backend.app.services import mitre as mitre_svc
    mitre_svc.load_bundle()

    register_error_handlers(app)
    register_cli(app)

    static_root = Path(static_folder)

    @app.get("/api/health")
    def health():
        return {"status": "ok"}, 200

    # Serve the built frontend (Vite output copied into app/static at image build time).
    @app.get("/")
    def index():
        index_path = static_root / "index.html"
        if index_path.exists():
            return send_from_directory(static_folder, "index.html")
        return {"status": "ok", "message": "Mimic API running. Frontend not built."}, 200

    @app.get("/<path:path>")
    def spa_fallback(path: str):
        # Unknown /api/* paths must stay JSON 404 — never shadowed by index.html.
        if path.startswith("api/"):
            return jsonify({"error": "Not found"}), 404
        # Serve static assets if present; otherwise hand back index.html for client routing.
        candidate = static_root / path
        if candidate.is_file():
            return send_from_directory(static_folder, path)
        index_path = static_root / "index.html"
        if index_path.exists():
            return send_from_directory(static_folder, "index.html")
        return jsonify({"error": "Not found"}), 404

    return app
