"""Error Pattern domain model for Predictive Error Prevention (Layer 4)."""

from __future__ import annotations

from datetime import UTC, datetime

from pydantic import BaseModel, Field
from ulid import ULID


class ErrorPattern(BaseModel, frozen=True):
    """A recorded error pattern with failure history and preventive checks."""

    pattern_id: str = Field(default_factory=lambda: str(ULID()))
    pattern: str = Field(min_length=1, description="Description of the error pattern")
    historical_failures: tuple[str, ...] = Field(
        default_factory=tuple,
        description="List of historical failure descriptions matching this pattern",
    )
    preventive_checks: tuple[str, ...] = Field(
        default_factory=tuple,
        description="List of preventive check descriptions to apply",
    )
    frequency: int = Field(
        default=1, ge=1, description="Number of times pattern was observed"
    )
    created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
    last_seen: datetime = Field(default_factory=lambda: datetime.now(UTC))

    # Keywords extracted from pattern for matching
    keywords: tuple[str, ...] = Field(
        default_factory=tuple,
        description="Keywords for pattern matching against plan context",
    )


class PreventiveGuidance(BaseModel, frozen=True):
    """Guidance to inject into actor context before plan execution."""

    matched_patterns: tuple[ErrorPattern, ...] = Field(default_factory=tuple)
    preventive_checks: tuple[str, ...] = Field(default_factory=tuple)

    @property
    def has_guidance(self) -> bool:
        """Return True if there are any preventive checks."""
        return len(self.preventive_checks) > 0

    def format_for_context(self) -> str:
        """Format preventive guidance as text for inclusion in actor context."""
        if not self.has_guidance:
            return ""
        lines: list[str] = ["[PREVENTIVE GUIDANCE — from Error Pattern Database]"]
        for i, check in enumerate(self.preventive_checks, 1):
            lines.append(f"  {i}. {check}")
        return "\n".join(lines)
