"""
Path Token Encryption

Encrypts file paths into opaque, time-limited Fernet tokens so raw filesystem
paths are never exposed in API URLs.

    encode_path("/opt/immich/paid/creator/file.mp4")
    # => "gAAAAABn..."   (URL-safe, 4-hour TTL)

    decode_path("gAAAAABn...")
    # => "/opt/immich/paid/creator/file.mp4"
"""

import base64
from pathlib import Path

from cryptography.fernet import Fernet, InvalidToken
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes
from fastapi import HTTPException


def _get_fernet() -> Fernet:
    """Derive a Fernet key from .session_secret via HKDF (cached after first call)."""
    if not hasattr(_get_fernet, "_instance"):
        from ..core.config import settings
        secret_path = settings.PROJECT_ROOT / ".session_secret"
        secret = secret_path.read_text().strip().encode()

        derived = HKDF(
            algorithm=hashes.SHA256(),
            length=32,
            salt=b"path-token-v1",
            info=b"fernet-key",
        ).derive(secret)

        key = base64.urlsafe_b64encode(derived)
        _get_fernet._instance = Fernet(key)
    return _get_fernet._instance


def encode_path(file_path: str) -> str:
    """Encrypt a file path into a URL-safe Fernet token (4-hour TTL)."""
    f = _get_fernet()
    return f.encrypt(file_path.encode()).decode()


def decode_path(token: str) -> str:
    """Decrypt a Fernet token back to a file path.

    Raises HTTP 400 on invalid or expired tokens (TTL = 4 hours).
    """
    f = _get_fernet()
    try:
        return f.decrypt(token.encode(), ttl=14400).decode()
    except InvalidToken:
        raise HTTPException(status_code=400, detail="Invalid or expired file token")
