"""Built-in command validators for common validation patterns."""

from __future__ import annotations


class DefaultValidator:
    """Default validator: exit code 0 AND produced data.

    Validates that:
    - Exit code is 0
    - Command ran for at least min_duration seconds
    - Command produced at least min_parameters data points
    """

    def __init__(
        self,
        min_duration: float = 2.0,
        min_parameters: int = 1,
        allow_no_data: bool = False,
    ):
        """
        Args:
            min_duration: Minimum execution time (prevents false positives on quick failures)
            min_parameters: Minimum parameter events required
            allow_no_data: If True, don't require parameter output
        """
        self.min_duration = min_duration
        self.min_parameters = min_parameters
        self.allow_no_data = allow_no_data

    def validate(
        self,
        exit_code: int,
        stdout: str,
        stderr: str,
        duration: float,
        parameter_count: int = 0,
    ) -> tuple[bool, str | None]:
        """Validate command execution."""
        # Check exit code
        if exit_code != 0:
            return False, f"Non-zero exit code: {exit_code}"

        # Check duration (avoid false positives on instant failures)
        if duration < self.min_duration:
            return (
                False,
                f"Command too short: {duration:.1f}s (min {self.min_duration}s)",
            )

        # Check data production
        if not self.allow_no_data and parameter_count < self.min_parameters:
            return (
                False,
                f"No data produced ({parameter_count} parameters, need {self.min_parameters})",
            )

        return True, None


class ExitCodeOnlyValidator:
    """Simple validator that only checks exit code.

    Use for commands that don't produce parseable data but still need
    to succeed (e.g., setup commands, cleanups).
    """

    def validate(
        self,
        exit_code: int,
        stdout: str,
        stderr: str,
        duration: float,
        parameter_count: int = 0,
    ) -> tuple[bool, str | None]:
        """Validate command execution."""
        if exit_code != 0:
            # Try to extract useful error from stderr
            error_lines = [line for line in stderr.split("\n") if line.strip()]
            if error_lines:
                first_error = error_lines[0][:100]
                return False, f"Exit {exit_code}: {first_error}"
            return False, f"Exit code: {exit_code}"
        return True, None


class OutputPatternValidator:
    """Validator that checks for expected patterns in output.

    Use for commands where success is indicated by specific output text.
    """

    def __init__(
        self,
        success_pattern: str | None = None,
        failure_pattern: str | None = None,
        check_stderr: bool = True,
    ):
        """
        Args:
            success_pattern: Pattern that must appear in output
            failure_pattern: Pattern that indicates failure
            check_stderr: Whether to also check stderr
        """
        self.success_pattern = success_pattern
        self.failure_pattern = failure_pattern
        self.check_stderr = check_stderr

    def validate(
        self,
        exit_code: int,
        stdout: str,
        stderr: str,
        duration: float,
        parameter_count: int = 0,
    ) -> tuple[bool, str | None]:
        """Validate command execution."""
        output = stdout
        if self.check_stderr:
            output += "\n" + stderr

        # Check for failure patterns first
        if self.failure_pattern and self.failure_pattern in output:
            return False, f"Failure pattern found: {self.failure_pattern}"

        # Check for success patterns
        if self.success_pattern and self.success_pattern not in output:
            return False, f"Success pattern not found: {self.success_pattern}"

        # Fall back to exit code
        if exit_code != 0:
            return False, f"Exit code: {exit_code}"

        return True, None
