"""Policy validation using capability-based allowlist.

This module provides the main validation function that:
1. Parses a command to extract operations
2. Checks each operation against a capability set
3. Raises PolicyError with clear guidance if anything is not permitted

This replaces the old token-based denylist validation.
"""

from rpipe.capability import CapabilitySet, OperationType, PolicyError
from rpipe.command_parser import CommandParser, ParseError, UnsupportedSyntaxError


def validate_command_against_capabilities(
    cmd: str, capability_set: CapabilitySet
) -> None:
    """
    Validate that command only performs operations permitted by capability set.

    This is the main entry point for v1 policy validation.

    Args:
        cmd: Command string to execute
        capability_set: CapabilitySet defining allowed operations

    Raises:
        PolicyError: If command performs unpermitted operations
        ParseError: If command syntax is invalid
        UnsupportedSyntaxError: If command uses unsupported syntax

    Algorithm:
        1. Parse command to extract binary, arguments, input/output files
        2. Check EXECUTE_BINARY permission for the binary
        3. Check READ_FILE permission for each input file
        4. Check WRITE_FILE permission for each output file
        5. Check stream permissions (stdin, stdout, stderr)
        6. If any check fails, raise PolicyError with guidance

    Examples:
        # Read-only policy
        cap_set = CapabilitySet([
            Capability(OperationType.READ_FILE, "/var/log/*"),
            Capability(OperationType.EXECUTE_BINARY, "cat|grep"),
            Capability(OperationType.WRITE_STDOUT, None),
        ])

        # This succeeds
        validate_command_against_capabilities("cat /var/log/syslog", cap_set)

        # This fails: no WRITE_FILE permission
        validate_command_against_capabilities("echo hello > /tmp/file", cap_set)
        # → PolicyError: "write_file on '/tmp/file' not permitted"

        # This fails: rm not in EXECUTE_BINARY
        validate_command_against_capabilities("rm /tmp/file", cap_set)
        # → PolicyError: "execute_binary on 'rm' not permitted"
    """
    # Parse command to extract operations
    try:
        parsed = CommandParser.parse(cmd)
    except UnsupportedSyntaxError as e:
        # Re-raise unsupported syntax errors with better context
        raise PolicyError(
            f"Command uses unsupported syntax:\n{e}\n\n"
            f"Supported in v1: simple commands with basic redirects (>, >>)\n"
            f"Example: cat /var/log/syslog\n"
            f"Example: grep error /var/log/* > /tmp/output"
        ) from e
    except ParseError as e:
        raise PolicyError(f"Invalid command syntax: {e}") from e

    # Check EXECUTE_BINARY permission
    capability_set.check_allowed(OperationType.EXECUTE_BINARY, parsed.binary)

    # Check READ_FILE permissions for input files
    for file_path in parsed.input_files:
        capability_set.check_allowed(OperationType.READ_FILE, file_path)

    # Check WRITE_FILE permissions for output files
    for file_path in parsed.output_files:
        capability_set.check_allowed(OperationType.WRITE_FILE, file_path)

    # Check stream permissions
    if parsed.uses_stdin:
        capability_set.check_allowed(OperationType.READ_STDIN)

    if parsed.uses_stdout:
        capability_set.check_allowed(OperationType.WRITE_STDOUT)

    if parsed.uses_stderr:
        capability_set.check_allowed(OperationType.WRITE_STDERR)
