"""Identifier generation for agents and instances.

Pure logic: generates unique IDs with appropriate prefixes.
No I/O imports.
"""

import uuid

from deal import post, pre



# @invar:allow missing_contract: Pure validation helper called from @pre contract
def _is_valid_instance_id_structure(instance_id: str) -> bool:
    """Check if instance_id meets ALL security constraints.

    Used by @pre contract to reject invalid inputs before function execution.

    Validates:
    - Is a non-empty string
    - Printable characters only
    - No path separators (/, \\)
    - No parent directory references (..)
    - No hidden file prefix (.)
    - Reasonable length (<= 256 chars)

    Returns:
        True if instance_id is safe for filesystem paths, False otherwise.
    """
    MAX_INSTANCE_ID_LENGTH = 256

    if not isinstance(instance_id, str):
        return False
    if len(instance_id) == 0:
        return False
    if len(instance_id) > MAX_INSTANCE_ID_LENGTH:
        return False
    if not instance_id.isprintable():
        return False
    if "/" in instance_id or "\\" in instance_id:
        return False
    if ".." in instance_id:
        return False
    if instance_id.startswith("."):
        return False
    return True


@pre(lambda prefix: isinstance(prefix, str) and len(prefix) > 0)
@post(lambda result: "_" in result and len(result) > 3)
def generate_id(prefix: str) -> str:
    """Generate a unique ID with the given prefix.

    Args:
        prefix: The prefix for the ID (e.g., 'ag', 'inst').

    Returns:
        A unique ID string.

    >>> aid = generate_id("ag")
    >>> aid.startswith("ag_")
    True
    >>> len(aid) > 3
    True
    >>> iid = generate_id("inst")
    >>> iid.startswith("inst_")
    True
    """
    return f"{prefix}_{uuid.uuid4().hex[:12]}"


@post(lambda result: result.startswith("inst_") and len(result) > 5)
def generate_instance_id() -> str:
    """Generate a unique instance ID with 'inst_' prefix.

    Returns:
        Instance ID with 'inst_' prefix.

    >>> iid = generate_instance_id()
    >>> iid.startswith("inst_")
    True
    >>> len(iid) > 5
    True
    """
    return generate_id("inst")


@post(lambda result: result.startswith("tr_") and len(result) > 3)
def generate_trace_id() -> str:
    """Generate a unique trace ID with 'tr_' prefix.

    Per docs/INTERFACES.md Section E, trace_id is generated by anima at job start
    and propagated to sub-agents for end-to-end tracing.

    Returns:
        Trace ID with 'tr_' prefix.

    >>> tid = generate_trace_id()
    >>> tid.startswith("tr_")
    True
    >>> len(tid) > 3
    True
    """
    return generate_id("tr")


@pre(lambda instance_id: _is_valid_instance_id_structure(instance_id))
def validate_instance_id(instance_id: str) -> str:
    """Validate instance_id to prevent path traversal attacks.

    Invariant: instance_id must be safe to use in filesystem paths.
    Rejects any instance_id that could be used for directory traversal.

    Security guarantees:
    - No path separators (/, \\)
    - No parent directory references (..)
    - No hidden files (.)
    - Only printable ASCII characters
    - Reasonable length limits

    Args:
        instance_id: User-provided instance ID

    Returns:
        The validated instance_id (unchanged if valid)

    Raises:
        InvalidInputError: If instance_id contains unsafe characters
        PreContractError: If instance_id fails contract validation

    Examples:
        >>> validate_instance_id("inst_abc123")
        'inst_abc123'

        >>> validate_instance_id("../../../etc/passwd")  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        PreContractError: ...

        >>> validate_instance_id("")  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        PreContractError: ...

        >>> validate_instance_id("inst/../../../etc")  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        PreContractError: ...

        >>> validate_instance_id(".hidden")  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        PreContractError: ...

        >>> validate_instance_id("a" * 300)  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        PreContractError: ...
    """
    # All validation is done by @pre contract
    # Function body is identity - just return the validated input
    return instance_id
