"""Core type definitions for Tru-Guard."""

from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Callable


class ScanType(Enum):
    """Types of content that can be scanned."""

    INPUT = "input"
    OUTPUT = "output"


class MatchType(Enum):
    """Types of regex matching strategies."""

    WHITELIST = "whitelist"  # Content must match regex to pass
    BLACKLIST = "blacklist"  # Content must NOT match regex to pass


class ActionType(Enum):
    """Types of actions that can be taken on scan failures."""

    FIX = "fix"
    MASK = "mask"
    ENCRYPT = "encrypt"
    FILTER = "filter"
    FAIL = "fail"
    IGNORE = "ignore"
    CUSTOM = "custom"


class ExecutionMode(Enum):
    """Execution modes for running scanners."""

    PARALLEL = "parallel"
    SEQUENTIAL = "sequential"
    PIPELINE = "pipeline"


class ConflictStrategy(Enum):
    """Strategies for resolving action conflicts."""

    PRIORITY = "priority"  # Use ACTION_PRIORITY order
    FIRST_WINS = "first_wins"  # First scanner's action wins
    RAISE_ERROR = "raise_error"  # Raise on conflict


class Severity(Enum):
    """Severity levels for violations."""

    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"


@dataclass
class Violation:
    """Represents a single violation detected by a scanner."""

    rule: str
    severity: Severity
    message: str
    span: tuple[int, int] | None = None  # Character positions (start, end)
    metadata: dict[str, Any] = field(default_factory=dict)

    def __post_init__(self) -> None:
        """Convert string severity to enum if needed."""
        if isinstance(self.severity, str):
            self.severity = Severity(self.severity)


@dataclass
class ScanResult:
    """Result from a single scanner execution."""

    passed: bool
    scanner_name: str
    scan_type: ScanType
    violations: list[Violation] = field(default_factory=list)
    suggested_fix: str | None = None
    metadata: dict[str, Any] = field(default_factory=dict)
    execution_time_ms: float = 0.0

    def __post_init__(self) -> None:
        """Convert string scan_type to enum if needed."""
        if isinstance(self.scan_type, str):
            self.scan_type = ScanType(self.scan_type)


@dataclass
class ActionRecord:
    """Record of an action taken during scanning."""

    action_type: ActionType
    scanner_name: str
    original_content: str
    modified_content: str | None
    timestamp: float

    def __post_init__(self) -> None:
        """Convert string action_type to enum if needed."""
        if isinstance(self.action_type, str):
            self.action_type = ActionType(self.action_type)


@dataclass
class AggregatedResult:
    """Aggregated result from all scanners."""

    passed: bool
    results: list[ScanResult] = field(default_factory=list)
    final_content: str | None = None  # Content after all actions applied
    actions_taken: list[ActionRecord] = field(default_factory=list)
    total_execution_time_ms: float = 0.0

    @property
    def failed_scanners(self) -> list[str]:
        """Get names of scanners that failed."""
        return [r.scanner_name for r in self.results if not r.passed]

    @property
    def all_violations(self) -> list[Violation]:
        """Get all violations from all scanners."""
        violations: list[Violation] = []
        for result in self.results:
            violations.extend(result.violations)
        return violations


@dataclass
class ScanContext:
    """Context information for a scan operation."""

    scan_type: ScanType
    prompt: str | None = None
    response: str | None = None
    metadata: dict[str, Any] = field(default_factory=dict)

    def __post_init__(self) -> None:
        """Convert string scan_type to enum if needed."""
        if isinstance(self.scan_type, str):
            self.scan_type = ScanType(self.scan_type)

    def get_content(self) -> str:
        """Get the content to scan based on scan type."""
        if self.scan_type == ScanType.INPUT:
            return self.prompt or ""
        elif self.scan_type == ScanType.OUTPUT:
            return self.response or ""
        else:
            # Fallback: return prompt if available, otherwise response
            return self.prompt or self.response or ""


@dataclass
class ScannerMetadata:
    """Metadata about a registered scanner."""

    name: str
    scan_types: list[ScanType]
    parameters: dict[str, Any] = field(default_factory=dict)
    description: str = ""


# Type alias for custom action functions
CustomActionFunc = Callable[[ScanResult, str], str | None]
