"""Filesystem path helpers — destination derivation, hash-suffixed names."""

import re
from pathlib import Path

_MAX_EXT_LEN = 16

# A Patreon/gallery CDN URL embeds a 32-char hex (MD5) path segment that is the
# file's stable per-file identity — the same role gallery-dl's `_filehash`
# plays. It is the join key between a post body `<img src=CDN>` and the local
# copy we downloaded (extract_media dedups content vs gallery images by it), so
# this ONE extractor must be used for both capture-time persistence and
# render-time matching — they cannot be allowed to drift. Match the FIRST 32-hex
# run anywhere in the URL (path or query); real CDN URLs carry exactly one.
_FILEHASH_RE = re.compile(r"([0-9a-fA-F]{32})")


def filehash_from_url(url: str | None) -> str | None:
    """The 32-char hex (MD5) CDN identity segment of `url`, lowercased, or None
    when the URL is empty / carries no such segment."""
    if not url:
        return None
    match = _FILEHASH_RE.search(url)
    return match.group(1).lower() if match else None


def safe_ext(name: str | Path) -> str:
    """Conservatively extract a short, alphanumeric file extension.

    gallery-dl and Patreon CDN URLs produce basenames with URL-encoded
    query-string artifacts, so `Path.suffix` can return 50+ chars of base64-ish
    junk that blows bounded VARCHAR columns (e.g. PostAttachment.ext varchar(32)).
    Accept only a suffix ≤16 chars whose post-dot characters are all alphanumeric;
    otherwise return "" (no known extension). Operator-flagged 2026-05-25 — ONE
    impl for the importer and the native Patreon client.
    """
    suffix = Path(name).suffix.lower()
    if not suffix or len(suffix) > _MAX_EXT_LEN:
        return ""
    if not all(c.isalnum() for c in suffix[1:]):
        return ""
    return suffix


def derive_subdir(source_path: Path, import_root: Path) -> str:
    """Returns the relative subdirectory of source_path under import_root.

    The top-level folder name is treated as the 'artist' bucket. Nested
    paths preserve hierarchy.

        import_root=/import
        source_path=/import/Alice/sub/x.png -> "Alice/sub"
        source_path=/import/Alice/x.png      -> "Alice"
        source_path=/import/x.png             -> ""
    """
    try:
        rel = source_path.parent.relative_to(import_root)
    except ValueError:
        return ""
    return str(rel) if str(rel) != "." else ""


def hash_suffixed_name(stem: str, sha256_hex: str, ext: str) -> str:
    """Builds 'stem__<first10ofhash><ext>'.

    Examples:
        hash_suffixed_name("photo", "abcdef1234567890...", ".png")
            -> "photo__abcdef1234.png"
    """
    return f"{stem}__{sha256_hex[:10]}{ext}"


def derive_top_level_artist(source_path: Path, import_root: Path) -> str | None:
    """Returns the top-level folder name under import_root, or None if the
    file is directly in import_root.
    """
    subdir = derive_subdir(source_path, import_root)
    if not subdir:
        return None
    return subdir.split("/", 1)[0]
