"""Data models for the MCP protocol validator."""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Callable

from hatchdx import HdxError


class ValidatorError(HdxError):
    """Raised when the validator encounters an unrecoverable problem."""


@dataclass
class ValidationRule:
    """A single validation check that can be run against tool definitions."""

    name: str
    category: str  # "naming", "schema", "annotations", "errors", "response", "pagination"
    severity: str  # "error", "warning", "info"
    description: str  # Human-readable explanation
    check: Callable[..., list[ValidationResult]]  # Function that runs the check

    def __post_init__(self) -> None:
        valid_categories = {
            "naming", "schema", "annotations", "errors", "response", "pagination",
        }
        if self.category not in valid_categories:
            raise ValueError(
                f"Invalid category '{self.category}'. "
                f"Must be one of: {', '.join(sorted(valid_categories))}"
            )

        valid_severities = {"error", "warning", "info"}
        if self.severity not in valid_severities:
            raise ValueError(
                f"Invalid severity '{self.severity}'. "
                f"Must be one of: {', '.join(sorted(valid_severities))}"
            )


@dataclass
class ValidationResult:
    """The outcome of a single validation check."""

    rule: ValidationRule
    passed: bool
    message: str  # Details on what passed/failed
    tool_name: str | None = None  # Which tool triggered it (if tool-specific)


@dataclass
class ValidationReport:
    """Aggregated results from running all validation rules."""

    results: list[ValidationResult] = field(default_factory=list)
    server_name: str = ""
    tools_checked: int = 0
    timestamp: datetime = field(default_factory=datetime.now)

    @property
    def passed_count(self) -> int:
        return sum(1 for r in self.results if r.passed)

    @property
    def failed_count(self) -> int:
        return sum(1 for r in self.results if not r.passed)

    @property
    def error_count(self) -> int:
        return sum(
            1 for r in self.results
            if not r.passed and r.rule.severity == "error"
        )

    @property
    def warning_count(self) -> int:
        return sum(
            1 for r in self.results
            if not r.passed and r.rule.severity == "warning"
        )

    @property
    def info_count(self) -> int:
        return sum(
            1 for r in self.results
            if not r.passed and r.rule.severity == "info"
        )

    @property
    def has_errors(self) -> bool:
        return self.error_count > 0
