"""Session folder path normalization and validation helpers for Studio."""

from __future__ import annotations

import re
from pathlib import Path, PurePosixPath

_SESSION_NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]*$")


def validate_session_name(name: str) -> str:
    """Validate a single session folder name (no path separators)."""
    candidate = (name or "").strip()
    if not candidate:
        raise ValueError("Session folder name is required")
    if candidate in {".", ".."}:
        raise ValueError("Invalid session folder name")
    if "/" in candidate or "\\" in candidate:
        raise ValueError("Session folder name cannot contain path separators")
    if not _SESSION_NAME_RE.fullmatch(candidate):
        raise ValueError(
            "Session folder name can only contain letters, numbers, '.', '_', and '-'"
        )
    return candidate


def normalize_session_folder_arg(session_folder: str) -> str:
    """Normalize session folder CLI/API input to '.mixer/sessions/<path>'.

    Supports nested paths like 'parent/child', 'sessions/parent/child',
    or '.mixer/sessions/parent/child'.
    """
    raw = (session_folder or "").strip()
    if not raw:
        return ""

    raw = raw.replace("\\", "/")
    pure = PurePosixPath(raw)
    if pure.is_absolute():
        raise ValueError("session_folder must be relative")

    parts = list(pure.parts)
    if not parts or any(part in {".", ".."} for part in parts):
        raise ValueError("Invalid session_folder path")

    # Strip known prefixes
    if len(parts) >= 2 and parts[0] == ".mixer" and parts[1] == "sessions":
        parts = parts[2:]
    elif len(parts) >= 1 and parts[0] == "sessions":
        parts = parts[1:]

    if not parts:
        raise ValueError("session_folder name is required")

    # Validate each segment
    for seg in parts:
        validate_session_name(seg)

    return ".mixer/sessions/" + "/".join(parts)


def session_name_from_folder_arg(session_folder: str) -> str:
    """Extract validated session name (possibly nested) from a session_folder argument."""
    normalized = normalize_session_folder_arg(session_folder)
    if not normalized:
        raise ValueError("session_folder is required")
    # Strip the '.mixer/sessions/' prefix to get the relative name
    prefix = ".mixer/sessions/"
    if normalized.startswith(prefix):
        return normalized[len(prefix):]
    return PurePosixPath(normalized).name


def resolve_session_path(sessions_dir: Path, name: str) -> Path:
    """Resolve and validate a session path under sessions_dir.

    Supports nested paths like 'parent/child' — each segment is validated.
    """
    root = sessions_dir.resolve()
    raw = (name or "").strip().replace("\\", "/")
    if not raw:
        raise ValueError("Session folder name is required")
    segments = [s for s in raw.split("/") if s]
    if not segments or any(s in {".", ".."} for s in segments):
        raise ValueError("Invalid session folder path")
    for seg in segments:
        validate_session_name(seg)
    candidate = root.joinpath(*segments).resolve()
    # Ensure it stays under sessions_dir
    if not candidate.is_relative_to(root):
        raise ValueError("Invalid session folder path")
    return candidate
