"""Exception hierarchy for Tru-Guard."""

from typing import Any


class TruGuardError(Exception):
    """Base exception for all Tru-Guard errors."""

    pass


class ScannerError(TruGuardError):
    """Error during scanner execution."""

    def __init__(self, scanner_name: str, message: str) -> None:
        self.scanner_name = scanner_name
        self.message = message
        super().__init__(f"Scanner '{scanner_name}': {message}")


class ScannerTimeoutError(ScannerError):
    """Scanner exceeded timeout."""

    def __init__(self, scanner_name: str, timeout: float) -> None:
        self.timeout = timeout
        super().__init__(scanner_name, f"Exceeded timeout of {timeout}s")


class ScannerValidationError(ScannerError):
    """Scanner input validation failed."""

    def __init__(self, scanner_name: str, validation_errors: list[str]) -> None:
        self.validation_errors = validation_errors
        errors_str = "; ".join(validation_errors)
        super().__init__(scanner_name, f"Validation failed: {errors_str}")


class ScannerExecutionError(ScannerError):
    """Scanner failed during execution."""

    def __init__(self, scanner_name: str, original_error: Exception) -> None:
        self.original_error = original_error
        super().__init__(scanner_name, f"Execution failed: {original_error}")


class ActionError(TruGuardError):
    """Error during action execution."""

    def __init__(self, action_type: str, message: str) -> None:
        self.action_type = action_type
        self.message = message
        super().__init__(f"Action '{action_type}': {message}")


class ActionConflictError(ActionError):
    """Multiple conflicting actions detected."""

    def __init__(self, conflicts: list[str]) -> None:
        self.conflicts = conflicts
        super().__init__("conflict", f"Conflicting actions: {conflicts}")


class ActionExecutionError(ActionError):
    """Action failed during execution."""

    def __init__(self, action_type: str, original_error: Exception) -> None:
        self.original_error = original_error
        super().__init__(action_type, f"Execution failed: {original_error}")


class ConfigurationError(TruGuardError):
    """Invalid configuration."""

    def __init__(self, message: str, parameter: str | None = None) -> None:
        self.parameter = parameter
        if parameter:
            message = f"Configuration error for '{parameter}': {message}"
        super().__init__(message)


class RegistryError(TruGuardError):
    """Scanner registry error."""

    def __init__(self, message: str) -> None:
        super().__init__(message)


class ScannerNotFoundError(RegistryError):
    """Scanner not found in registry."""

    def __init__(self, scanner_name: str) -> None:
        self.scanner_name = scanner_name
        super().__init__(f"Scanner '{scanner_name}' not found in registry")


class ScannerAlreadyRegisteredError(RegistryError):
    """Scanner already registered with the same name."""

    def __init__(self, scanner_name: str) -> None:
        self.scanner_name = scanner_name
        super().__init__(f"Scanner '{scanner_name}' is already registered")


class ScanFailedError(TruGuardError):
    """Raised when a scan fails and action is FAIL."""

    def __init__(
        self,
        scanner_name: str,
        violations: list[Any],
        message: str = "Scan failed due to violations",
    ) -> None:
        self.scanner_name = scanner_name
        self.violations = violations
        # Set by execution runner when re-raising so guard can save result before exit
        self.aggregated_result: Any = None
        super().__init__(f"{message} (scanner: {scanner_name}, violations: {len(violations)})")
