"""
Validation Error Models for Issue #8: Get Validation Errors.

This module provides structured error reporting for schema validation failures,
enabling detailed feedback for arc42 compliance checking and user guidance.
"""

from typing import List, Dict, Any, Optional
from dataclasses import dataclass
from enum import Enum


class ValidationErrorType(Enum):
    """Types of validation errors that can occur during schema validation."""

    MISSING_REQUIRED_HEADING = "missing_required_heading"
    UNEXPECTED_HEADING = "unexpected_heading"
    INSUFFICIENT_CONTENT = "insufficient_content"
    EXCESS_CONTENT = "excess_content"
    MISSING_REQUIRED_SECTION = "missing_required_section"
    HEADING_COUNT_MISMATCH = "heading_count_mismatch"
    CONTENT_COUNT_MISMATCH = "content_count_mismatch"
    STRUCTURAL_VIOLATION = "structural_violation"


@dataclass
class ValidationError:
    """
    Represents a specific validation error with detailed information.

    This class provides structured error information that can be used
    to generate user-friendly error messages and guide compliance fixing.
    """

    error_type: ValidationErrorType
    message: str
    path: str  # JSON path or section identifier
    expected: Optional[Any] = None
    actual: Optional[Any] = None
    suggestion: Optional[str] = None
    severity: str = "error"  # error, warning, info

    def __str__(self) -> str:
        """Return a formatted error message for display."""
        return self.message


class ValidationErrorCollector:
    """
    Collects and manages validation errors during schema validation.

    This class accumulates validation errors and provides methods to
    format and present them in user-friendly ways.
    """

    def __init__(self):
        """Initialize empty error collector."""
        self.errors: List[ValidationError] = []

    def add_error(
        self,
        error_type: ValidationErrorType,
        message: str,
        path: str,
        expected: Optional[Any] = None,
        actual: Optional[Any] = None,
        suggestion: Optional[str] = None,
        severity: str = "error"
    ) -> None:
        """Add a validation error to the collection."""
        error = ValidationError(
            error_type=error_type,
            message=message,
            path=path,
            expected=expected,
            actual=actual,
            suggestion=suggestion,
            severity=severity
        )
        self.errors.append(error)

    def has_errors(self) -> bool:
        """Check if any errors have been collected."""
        return len(self.errors) > 0

    def get_error_count(self) -> int:
        """Get the total number of errors."""
        return len(self.errors)

    def get_errors_by_type(self, error_type: ValidationErrorType) -> List[ValidationError]:
        """Get all errors of a specific type."""
        return [error for error in self.errors if error.error_type == error_type]

    def get_errors_by_severity(self, severity: str) -> List[ValidationError]:
        """Get all errors of a specific severity level."""
        return [error for error in self.errors if error.severity == severity]

    def format_errors(self, format_type: str = "text") -> str:
        """
        Format all errors for display.

        Args:
            format_type: Output format ('text', 'json', 'markdown')

        Returns:
            Formatted error string
        """
        if not self.errors:
            return "No validation errors found."

        if format_type == "json":
            import json
            error_data = [
                {
                    "type": error.error_type.value,
                    "message": error.message,
                    "path": error.path,
                    "expected": error.expected,
                    "actual": error.actual,
                    "suggestion": error.suggestion,
                    "severity": error.severity
                }
                for error in self.errors
            ]
            return json.dumps(error_data, indent=2)

        elif format_type == "markdown":
            lines = ["# Validation Errors\n"]

            # Group errors by severity
            error_groups = {}
            for error in self.errors:
                if error.severity not in error_groups:
                    error_groups[error.severity] = []
                error_groups[error.severity].append(error)

            for severity in ["error", "warning", "info"]:
                if severity in error_groups:
                    lines.append(f"## {severity.title()}s\n")
                    for error in error_groups[severity]:
                        lines.append(f"- **{error.path}**: {error.message}")
                        if error.expected is not None:
                            lines.append(f"  - Expected: {error.expected}")
                        if error.actual is not None:
                            lines.append(f"  - Actual: {error.actual}")
                        if error.suggestion:
                            lines.append(f"  - Suggestion: {error.suggestion}")
                        lines.append("")

            return "\n".join(lines)

        else:  # text format
            lines = []
            lines.append(f"Validation failed with {len(self.errors)} error(s):")
            lines.append("")

            for i, error in enumerate(self.errors, 1):
                lines.append(f"{i}. [{error.severity.upper()}] {error.path}")
                lines.append(f"   {error.message}")

                if error.expected is not None:
                    lines.append(f"   Expected: {error.expected}")
                if error.actual is not None:
                    lines.append(f"   Actual: {error.actual}")
                if error.suggestion:
                    lines.append(f"   💡 {error.suggestion}")
                lines.append("")

            return "\n".join(lines)

    def get_summary(self) -> Dict[str, int]:
        """Get a summary of error counts by type and severity."""
        summary = {
            "total_errors": len(self.errors),
            "by_severity": {},
            "by_type": {}
        }

        for error in self.errors:
            # Count by severity
            if error.severity not in summary["by_severity"]:
                summary["by_severity"][error.severity] = 0
            summary["by_severity"][error.severity] += 1

            # Count by type
            error_type_name = error.error_type.value
            if error_type_name not in summary["by_type"]:
                summary["by_type"][error_type_name] = 0
            summary["by_type"][error_type_name] += 1

        return summary