"""Profils SQLite : deux fichiers fixes, choisis à la connexion.

Le choix est stocké en session (`db_profile`). ProfileRoutingSession
dirige les requêtes ORM vers le bon fichier pour toute la session.
"""
from __future__ import annotations

from pathlib import Path

from flask import Flask, has_request_context, session
from flask_sqlalchemy.session import Session as FSQSession

from config import DATA_DIR

PROFILE_PROD = "prod"
PROFILE_IMPORT = "import"
DEFAULT_PROFILE = PROFILE_PROD

DATABASE_PROFILES: dict[str, dict[str, str | Path]] = {
    PROFILE_PROD: {
        "label": "Production",
        "path": DATA_DIR / "copropriete.db",
        "badge_class": "db-badge-prod",
    },
    PROFILE_IMPORT: {
        "label": "Import (test)",
        "path": DATA_DIR / "import-test.db",
        "badge_class": "db-badge-import",
    },
}


def sqlalchemy_binds() -> dict[str, str]:
    return {key: profile_uri(key) for key in DATABASE_PROFILES}


def profile_uri(key: str) -> str:
    if key not in DATABASE_PROFILES:
        key = DEFAULT_PROFILE
    path = Path(DATABASE_PROFILES[key]["path"]).resolve()
    return f"sqlite:///{path}"


def profile_label(key: str) -> str:
    return str(DATABASE_PROFILES.get(key, DATABASE_PROFILES[DEFAULT_PROFILE])["label"])


def profile_badge_class(key: str) -> str:
    return str(
        DATABASE_PROFILES.get(key, DATABASE_PROFILES[DEFAULT_PROFILE])["badge_class"]
    )


def profile_path(key: str) -> Path:
    return Path(DATABASE_PROFILES[key]["path"])


def session_profile_key() -> str:
    if not has_request_context():
        return DEFAULT_PROFILE
    key = session.get("db_profile", DEFAULT_PROFILE)
    if key not in DATABASE_PROFILES:
        return DEFAULT_PROFILE
    return key


def set_session_profile(key: str) -> None:
    if key not in DATABASE_PROFILES:
        key = DEFAULT_PROFILE
    session["db_profile"] = key
    session.pop("copropriete_id", None)
    clear_db_session()


def clear_db_session() -> None:
    """Évite les objets ORM attachés à l'ancienne base après un changement de profil."""
    try:
        from app.models import db

        db.session.remove()
    except Exception:
        pass


class ProfileRoutingSession(FSQSession):
    """Route les requêtes ORM vers prod ou import selon la session Flask."""

    def get_bind(self, mapper=None, clause=None, bind=None, **kwargs):
        if has_request_context():
            key = session_profile_key()
            engines = self._db.engines
            if key in engines:
                return engines[key]
        return super().get_bind(mapper=mapper, clause=clause, bind=bind, **kwargs)


def activate_profile(app: Flask, db, key: str) -> str:
    """Enregistre le profil en session (le moteur est choisi par ProfileRoutingSession)."""
    uri = profile_uri(key)
    app.config["_ACTIVE_DB_PROFILE"] = key
    return uri


def register_database_hooks(app: Flask, db) -> None:
    @app.before_request
    def _remember_database_profile():
        activate_profile(app, db, session_profile_key())
