"""
Authentication: read Better Auth session table, role decorators.

Better Auth (Node.js sidecar) handles login via Microsoft Entra SSO.
Flask validates sessions by reading the session/user tables directly.
"""

from datetime import datetime, timezone
from functools import wraps

from flask import (
    Blueprint, request, session, redirect, url_for, render_template, g,
)
from sqlalchemy import text

from icp_db import get_session as get_db_session

auth_bp = Blueprint("auth", __name__)

ROLE_HIERARCHY = {"admin": 3, "editor": 2, "viewer": 1}


# ---------------------------------------------------------------------------
# Session reading — Better Auth cookie → DB lookup
# ---------------------------------------------------------------------------

def _get_session_token():
    """Extract Better Auth session token from cookie.

    Better Auth sets a cookie named 'better-auth.session_token'.
    The value may have an HMAC suffix after the last '.' — strip it.
    """
    raw = (
        request.cookies.get("__Secure-better-auth.session_token")
        or request.cookies.get("better-auth.session_token")
    )
    if not raw:
        return None
    # Strip HMAC suffix (everything after last dot)
    parts = raw.rsplit(".", 1)
    return parts[0] if len(parts) == 2 and len(parts[1]) < 64 else raw


def get_current_user():
    """Look up the current user from Better Auth session table.

    Returns dict with id, name, email, role, image or None.
    Caches result on flask.g for the request lifetime.
    """
    if hasattr(g, "_current_user"):
        return g._current_user

    token = _get_session_token()
    if not token:
        g._current_user = None
        return None

    db = g.get("db") or get_db_session()
    row = db.execute(
        text('''
            SELECT u.id, u.name, u.email, u.role, u.image, s."expiresAt"
            FROM "session" s
            JOIN "user" u ON u.id = s."userId"
            WHERE s.token = :token
            LIMIT 1
        '''),
        {"token": token},
    ).mappings().first()

    if not row:
        g._current_user = None
        return None

    # Check expiry (DB stores naive UTC timestamps)
    expires_at = row["expiresAt"]
    if expires_at:
        if expires_at.tzinfo is None:
            expires_at = expires_at.replace(tzinfo=timezone.utc)
        if expires_at < datetime.now(timezone.utc):
            g._current_user = None
            return None

    user = {
        "id": row["id"],
        "name": row["name"],
        "email": row["email"],
        "role": row["role"] or "viewer",
        "image": row["image"],
    }
    g._current_user = user
    return user


# ---------------------------------------------------------------------------
# Inject user into Flask session for template access
# ---------------------------------------------------------------------------

def load_user_into_session():
    """Before-request hook: populate Flask session from Better Auth user."""
    user = get_current_user()
    if user:
        session["user_id"] = user["id"]
        session["username"] = user["name"] or user["email"]
        session["role"] = user["role"]
        session["email"] = user["email"]
    else:
        # Clear stale session data if no valid Better Auth session
        if "user_id" in session:
            session.clear()


# ---------------------------------------------------------------------------
# Decorators (same interface as before)
# ---------------------------------------------------------------------------

def login_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        if not get_current_user():
            return redirect(url_for("auth.login", next=request.path))
        return f(*args, **kwargs)
    return decorated


def role_required(minimum_role: str):
    """Decorator: requires the logged-in user to have at least *minimum_role*."""
    def decorator(f):
        @wraps(f)
        def decorated(*args, **kwargs):
            user = get_current_user()
            if not user:
                return redirect(url_for("auth.login", next=request.path))
            user_level = ROLE_HIERARCHY.get(user["role"], 1)
            required_level = ROLE_HIERARCHY.get(minimum_role, 1)
            if user_level < required_level:
                return render_template("base.html", error="Insufficient permissions."), 403
            return f(*args, **kwargs)
        return decorated
    return decorator


# ---------------------------------------------------------------------------
# Routes
# ---------------------------------------------------------------------------

@auth_bp.route("/login")
def login():
    """Show login page. If already authenticated, redirect to dashboard."""
    if get_current_user():
        return redirect(url_for("dashboard.index"))
    return render_template("login.html")


@auth_bp.route("/logout")
def logout():
    """Clear Flask session and redirect to login."""
    session.clear()
    return redirect(url_for("auth.login"))
