"""
MCLogger – Flask Web-Panel
Multi-Tenant mit Gruppen, Rollen & verschlüsselten DB-Zugangsdaten.
Coolify-kompatibel: alle Einstellungen via ENV.
"""
import secrets
from datetime import datetime
from flask import Flask, abort, render_template, request, session, url_for
from config import Config
from panel_db import init_databases, get_user_groups

from blueprints.auth        import auth
from blueprints.site_admin  import site_admin
from blueprints.group_admin import group_admin
from blueprints.panel       import panel


def create_app() -> Flask:
    app = Flask(__name__)
    app.secret_key = Config.SECRET_KEY
    app.config.update(
        SESSION_COOKIE_HTTPONLY=Config.SESSION_COOKIE_HTTPONLY,
        SESSION_COOKIE_SAMESITE=Config.SESSION_COOKIE_SAMESITE,
        SESSION_COOKIE_SECURE=Config.SESSION_COOKIE_SECURE,
    )

    Config.validate_security()

    # Blueprints registrieren
    app.register_blueprint(auth)
    app.register_blueprint(site_admin)
    app.register_blueprint(group_admin)
    app.register_blueprint(panel)

    # Panel-Datenbank-Tabellen anlegen
    try:
        init_databases()
    except Exception as e:
        app.logger.warning(f"DB-Initialisierung fehlgeschlagen (noch nicht konfiguriert?): {e}")

    # ── Template-Filter ───────────────────────────────────────

    def _get_or_create_csrf_token() -> str:
        token = session.get("_csrf_token")
        if not token:
            token = secrets.token_urlsafe(32)
            session["_csrf_token"] = token
        return token

    @app.before_request
    def enforce_csrf():
        if request.method not in {"POST", "PUT", "PATCH", "DELETE"}:
            return

        session_token = session.get("_csrf_token")
        request_token = request.form.get("_csrf_token") or request.headers.get("X-CSRF-Token")
        if not session_token or not request_token or session_token != request_token:
            abort(400)

    @app.after_request
    def set_security_headers(resp):
        resp.headers.setdefault("X-Content-Type-Options", "nosniff")
        resp.headers.setdefault("X-Frame-Options", "DENY")
        resp.headers.setdefault("Referrer-Policy", "strict-origin-when-cross-origin")
        resp.headers.setdefault("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data:; font-src 'self' https://cdn.jsdelivr.net; connect-src 'self'; frame-ancestors 'none';")
        return resp

    @app.errorhandler(400)
    def bad_request(_):
        return "Bad request", 400

    @app.errorhandler(404)
    def not_found(_):
        uid = session.get("user_id")
        is_site_admin = bool(session.get("is_site_admin"))
        role = session.get("role")

        links = []
        if not uid:
            links = [
                {"label": "Login", "href": url_for("auth.login"), "btn": "btn-success"},
                {"label": "Site Admin Login", "href": url_for("auth.admin_login"), "btn": "btn-outline-danger"},
            ]
        elif is_site_admin and not session.get("group_id"):
            links = [
                {"label": "Site Admin Dashboard", "href": url_for("site_admin.dashboard"), "btn": "btn-danger"},
            ]
        else:
            links.append({"label": "Panel Dashboard", "href": url_for("panel.dashboard"), "btn": "btn-success"})
            if is_site_admin:
                links.append({"label": "Site Admin", "href": url_for("site_admin.dashboard"), "btn": "btn-outline-danger"})
            if role == "admin" and not is_site_admin:
                links.append({"label": "Group Admin", "href": url_for("group_admin.dashboard"), "btn": "btn-outline-warning"})

        return render_template(
            "404.html",
            requested_path=request.path,
            request_method=request.method,
            links=links,
            is_logged_in=bool(uid),
            is_site_admin=is_site_admin,
            role=role,
        ), 404

    @app.template_filter("fmt_duration")
    def fmt_duration(seconds):
        if seconds is None:
            return "—"
        seconds = int(seconds)
        h = seconds // 3600
        m = (seconds % 3600) // 60
        s = seconds % 60
        if h:   return f"{h}h {m}m"
        elif m: return f"{m}m {s}s"
        return f"{s}s"

    @app.template_filter("fmt_dt")
    def fmt_dt(dt):
        if dt is None:
            return "—"
        if isinstance(dt, str):
            return dt
        return dt.strftime("%d.%m.%Y %H:%M:%S")

    @app.context_processor
    def inject_globals():
        uid = session.get("user_id")
        try:
            groups = get_user_groups(uid) if uid else []
        except Exception:
            groups = []
        return {
            "now":         datetime.now(),
            "app_version": "2.0.0",
            "author":      "SimolZimol",
            "user_groups": groups,
            "csrf_token":  _get_or_create_csrf_token,
        }

    return app


app = create_app()

if __name__ == "__main__":
    app.run(host=Config.HOST, port=Config.PORT, debug=Config.DEBUG)

