"""Filesystem + JWT metadata helpers — metadata only, never a secret value.

:func:`jwt_exp` reads a JWT file in-process to decode its ``exp`` claim and
returns the integer only; the token string never leaves the function (AG-18).
"""

from __future__ import annotations

import base64
import binascii
import json
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from pathlib import Path


def octal_mode(path: Path) -> str | None:
    try:
        return oct(path.stat().st_mode & 0o777)[2:]
    except OSError:
        return None


def nonblank_lines(path: Path) -> int:
    try:
        text = path.read_text(encoding="utf-8", errors="replace")
    except OSError:
        return 0
    return sum(1 for ln in text.splitlines() if ln.strip())


def jwt_exp(path: Path) -> float | None:
    """Decode a JWT ``exp`` claim in-process. Returns the epoch seconds only."""
    try:
        raw = path.read_text(encoding="utf-8", errors="replace").strip()
    except OSError:
        return None
    parts = raw.split(".")
    if len(parts) != 3:
        return None
    payload_b64 = parts[1]
    pad = "=" * (-len(payload_b64) % 4)
    try:
        payload = json.loads(base64.urlsafe_b64decode(payload_b64 + pad))
    except (binascii.Error, ValueError, json.JSONDecodeError):
        return None
    exp = payload.get("exp")
    return float(exp) if isinstance(exp, (int, float)) else None
