"""Unified validation error model.

Replaces the three incompatible error models previously used across
TokenMoulds (string lists, typed dataclass + enum, plain dicts) with
a single pair: ``ValidationIssue`` and ``ValidationReport``.

Field names and severity levels are aligned with openxml-audit's
``ValidationError`` / ``ValidationResult`` for interoperability.

See ADR 020, item 3.
"""

from __future__ import annotations

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


class Severity(Enum):
    """Issue severity levels."""

    ERROR = "error"  # Breaks functionality
    WARNING = "warning"  # May cause UX issues
    INFO = "info"  # Best practice suggestion


@dataclass(frozen=True)
class ValidationIssue:
    """A single validation issue."""

    code: str
    message: str
    severity: Severity
    location: Optional[str] = None
    suggestion: Optional[str] = None

    def to_dict(self) -> dict[str, Any]:
        d: dict[str, Any] = {
            "code": self.code,
            "message": self.message,
            "severity": self.severity.value,
        }
        if self.location is not None:
            d["location"] = self.location
        if self.suggestion is not None:
            d["suggestion"] = self.suggestion
        return d


@dataclass
class ValidationReport:
    """Collection of validation issues with convenience accessors.

    ``is_valid`` is derived: a report is valid when it contains no
    ERROR-severity issues.
    """

    issues: list[ValidationIssue] = field(default_factory=list)

    @property
    def is_valid(self) -> bool:
        return not any(i.severity is Severity.ERROR for i in self.issues)

    def add_issue(self, issue: ValidationIssue) -> None:
        self.issues.append(issue)

    def add_error(
        self,
        code: str,
        message: str,
        *,
        location: Optional[str] = None,
        suggestion: Optional[str] = None,
    ) -> None:
        self.add_issue(
            ValidationIssue(
                code=code,
                message=message,
                severity=Severity.ERROR,
                location=location,
                suggestion=suggestion,
            )
        )

    def add_warning(
        self,
        code: str,
        message: str,
        *,
        location: Optional[str] = None,
        suggestion: Optional[str] = None,
    ) -> None:
        self.add_issue(
            ValidationIssue(
                code=code,
                message=message,
                severity=Severity.WARNING,
                location=location,
                suggestion=suggestion,
            )
        )

    def add_info(
        self,
        code: str,
        message: str,
        *,
        location: Optional[str] = None,
        suggestion: Optional[str] = None,
    ) -> None:
        self.add_issue(
            ValidationIssue(
                code=code,
                message=message,
                severity=Severity.INFO,
                location=location,
                suggestion=suggestion,
            )
        )

    @property
    def errors(self) -> list[ValidationIssue]:
        return [i for i in self.issues if i.severity is Severity.ERROR]

    @property
    def warnings(self) -> list[ValidationIssue]:
        return [i for i in self.issues if i.severity is Severity.WARNING]

    @property
    def infos(self) -> list[ValidationIssue]:
        return [i for i in self.issues if i.severity is Severity.INFO]

    def to_dict(self) -> dict[str, Any]:
        return {
            "valid": self.is_valid,
            "errors": [i.to_dict() for i in self.errors],
            "warnings": [i.to_dict() for i in self.warnings],
            "info": [i.to_dict() for i in self.infos],
        }
