"""L1 分树路径 — data/{username}/ vs tenant_config/{username}/ · design §6.1。"""

from __future__ import annotations

from enum import Enum
from pathlib import Path, PurePosixPath

from niannian.tenant.registry import validate_username

L1_TREE_DATA = "data"
L1_TREE_TENANT_CONFIG = "tenant_config"

NAS_MIRROR_DIRNAME = "tenant_l1_mirror"

_RESERVED_SEGMENTS = frozenset({".", ".."})


class L1Tree(str, Enum):
    DATA = L1_TREE_DATA
    TENANT_CONFIG = L1_TREE_TENANT_CONFIG


def normalize_l1_tree(tree: str) -> str:
    value = str(tree).strip().lower()
    if value not in (L1_TREE_DATA, L1_TREE_TENANT_CONFIG):
        raise ValueError(f"invalid L1 tree: {tree!r}")
    return value


def l1_relative_dir(tree: str, username: str) -> str:
    t = normalize_l1_tree(tree)
    user = validate_username(username)
    return f"{t}/{user}/"


def nas_mirror_root(home: Path) -> Path:
    return Path(home) / "control" / NAS_MIRROR_DIRNAME


def nas_mirror_dir(home: Path, tree: str, username: str) -> Path:
    t = normalize_l1_tree(tree)
    user = validate_username(username)
    return nas_mirror_root(home) / t / user


def validate_relative_file_path(path: str, *, tree: str) -> str:
    """Validate a push file path; return normalized relative posix path."""
    t = normalize_l1_tree(tree)
    raw = str(path).strip()
    if not raw:
        raise ValueError("empty file path")

    p = PurePosixPath(raw.replace("\\", "/"))
    if p.is_absolute():
        raise ValueError(f"absolute path not allowed: {path!r}")

    parts = p.parts
    if not parts:
        raise ValueError(f"empty file path: {path!r}")
    for part in parts:
        if part in _RESERVED_SEGMENTS:
            raise ValueError(f"path traversal not allowed: {path!r}")

    normalized = "/".join(parts)
    if normalized.startswith(f"{L1_TREE_DATA}/") and t != L1_TREE_DATA:
        raise ValueError(f"file path violates L1 iron rule (data prefix on {t} tree): {path!r}")
    if normalized.startswith(f"{L1_TREE_TENANT_CONFIG}/") and t != L1_TREE_TENANT_CONFIG:
        raise ValueError(
            f"file path violates L1 iron rule (tenant_config prefix on {t} tree): {path!r}"
        )
    return normalized


def mirror_file_path(home: Path, tree: str, username: str, relative_path: str) -> Path:
    """Resolve a validated relative file path under the NAS mirror directory."""
    rel = validate_relative_file_path(relative_path, tree=tree)
    base = nas_mirror_dir(home, tree, username).resolve()
    target = (base / rel).resolve()
    if not str(target).startswith(str(base)):
        raise ValueError(f"path escapes mirror directory: {relative_path!r}")
    return target
