"""
Shared cache-path construction for downloaded ticket attachments.

This exists as its own module for one reason: the path is built in TWO places —
the /attachment/<id> route in main.py and the background prefetch beat in
tasks/maintenance_tasks.py. They previously each built it inline, and both used
`{attachment_id}_{filename}` in a single global directory.

That was a cross-tenant leak. `addons_attachments.id` is a per-schema serial, so
every tenant has an attachment 1, 2, 3…; two tenants whose attachment N happened
to share a filename resolved to the same file on disk, and whichever wrote last
won. These are end-customer support attachments — screenshots of back offices,
invoices, logs.

Keep the two call sites on this function. If they ever diverge again, the
prefetch task will quietly re-create the flat, colliding layout.
"""

from __future__ import annotations

import hashlib
import re
from pathlib import Path

#: Extensions we are willing to reproduce verbatim in a path. Anything else gets
#: no extension at all — the Content-Type header drives rendering, not the suffix.
_SAFE_EXT = re.compile(r"^[A-Za-z0-9]{1,8}$")


def attachment_cache_path(
    cache_dir: Path, schema: str, attachment_id: int, filename: str
) -> Path:
    """
    Return the on-disk cache path for one attachment, namespaced by tenant.

    `schema` is the tenant schema name (e.g. "tenant_acme"), which is assigned by
    us and never user-supplied, so it is safe as a directory component. The
    filename comes from the Addons API — a third party — so it is reduced to a
    short hash plus a strictly validated extension. That removes path traversal,
    absolute paths, control characters and length limits as concerns in one step,
    while keeping the path stable for a given attachment.
    """
    safe_schema = re.sub(r"[^A-Za-z0-9_]", "_", schema or "unknown")

    name = filename or ""
    ext = name.rsplit(".", 1)[-1] if "." in name else ""
    suffix = f".{ext.lower()}" if _SAFE_EXT.match(ext) else ""

    digest = hashlib.sha256(name.encode("utf-8", "replace")).hexdigest()[:16]

    tenant_dir = cache_dir / safe_schema
    tenant_dir.mkdir(parents=True, exist_ok=True)
    return tenant_dir / f"{attachment_id}_{digest}{suffix}"
