"""자료실 경로 유틸.

user_tags 내 @library/ 접두사 태그를 정규화·검증·추출한다.
"""

LIBRARY_PREFIX = "@library/"
DEFAULT_LIBRARY_PATH = "미분류"
MAX_DEPTH = 5
MAX_SEGMENT_LEN = 30


def normalize_library_path(raw: str) -> str:
    """경로 정규화. 엄격 정책 — 규칙 위반 시 ValueError 즉시 raise.

    규칙:
    - 앞뒤 공백·슬래시 제거
    - segment별 trim
    - 빈 segment(// 또는 공백만) → ValueError
    - segment 30자 초과 → ValueError
    - 5단계 초과 → ValueError

    GET /documents/library?path= 쿼리에도 동일하게 적용.
    """
    stripped = raw.strip().strip("/")
    if not stripped:
        raise ValueError("빈 경로")

    segments = stripped.split("/")
    normalized: list[str] = []
    for s in segments:
        s = s.strip()
        if not s:
            raise ValueError("빈 세그먼트 (// 또는 공백만 있는 구간)")
        if len(s) > MAX_SEGMENT_LEN:
            raise ValueError(f"세그먼트 '{s}'가 {MAX_SEGMENT_LEN}자 초과")
        normalized.append(s)

    if len(normalized) > MAX_DEPTH:
        raise ValueError(f"최대 {MAX_DEPTH}단계까지 가능")

    return "/".join(normalized)


def extract_library_paths(user_tags: list[str] | None) -> list[str]:
    """user_tags에서 @library/ 경로만 추출 (prefix 포함)."""
    if not user_tags:
        return []
    return [t for t in user_tags if t.startswith(LIBRARY_PREFIX)]


def validate_user_tags(tags: list) -> list[str]:
    """user_tags 전체 검증. 입력 순서 보존, 중복 제거.

    - 문자열이 아닌 원소 → TypeError
    - 빈 문자열 / 공백만 있는 태그 → 제거
    - 일반 태그 → strip() 후 통과
    - @library/ 태그 → normalize_library_path() 적용
    - 중복 → 첫 출현만 유지 (입력 순서 보존)
    """
    result: list[str] = []
    for tag in tags:
        if not isinstance(tag, str):
            raise TypeError(f"태그는 문자열이어야 합니다: {tag!r}")
        tag = tag.strip()
        if not tag:
            continue
        if tag.startswith(LIBRARY_PREFIX):
            path = tag[len(LIBRARY_PREFIX):]
            normalized = normalize_library_path(path)
            tag = f"{LIBRARY_PREFIX}{normalized}"
        result.append(tag)

    # 중복 제거 (입력 순서 보존)
    seen: set[str] = set()
    deduped: list[str] = []
    for t in result:
        if t not in seen:
            seen.add(t)
            deduped.append(t)
    return deduped
