"""JSON Schema validation for tool inputs and outputs.

Validates tool parameters against their declared ``input_schema`` and
validates tool results against their declared ``output_schema`` using
the ``jsonschema`` library (JSON Schema draft 2020-12).

Based on docs/specification.md Tool Execution Flow section.
"""

from __future__ import annotations

from typing import Any

import jsonschema
import jsonschema.validators

# ---------------------------------------------------------------------------
# Errors
# ---------------------------------------------------------------------------


class ToolSchemaValidationError(Exception):
    """Raised when tool input or output fails JSON Schema validation.

    Attributes
    ----------
    errors:
        List of individual validation error messages.
    schema:
        The JSON Schema that was used for validation.
    instance:
        The value that failed validation.
    """

    def __init__(
        self,
        message: str,
        *,
        errors: list[str] | None = None,
        schema: dict[str, Any] | None = None,
        instance: Any = None,
    ) -> None:
        super().__init__(message)
        self.errors = errors or []
        self.schema = schema
        self.instance = instance


# ---------------------------------------------------------------------------
# Validation functions
# ---------------------------------------------------------------------------


def validate_tool_input(
    params: dict[str, Any],
    schema: dict[str, Any],
) -> None:
    """Validate tool input parameters against a JSON Schema.

    Parameters
    ----------
    params:
        The parameters to validate.
    schema:
        The JSON Schema to validate against.

    Raises
    ------
    ToolSchemaValidationError:
        If validation fails, with details about each error.
    """
    _validate(params, schema, context="input")


def validate_tool_output(
    result: Any,
    schema: dict[str, Any],
) -> None:
    """Validate tool output against a JSON Schema.

    Parameters
    ----------
    result:
        The output to validate.
    schema:
        The JSON Schema to validate against.

    Raises
    ------
    ToolSchemaValidationError:
        If validation fails, with details about each error.
    """
    _validate(result, schema, context="output")


def _validate(
    instance: Any,
    schema: dict[str, Any],
    *,
    context: str,
) -> None:
    """Internal validation helper.

    Uses ``jsonschema.Draft202012Validator`` for JSON Schema draft 2020-12
    compliance (per spec).
    """
    validator_cls = jsonschema.Draft202012Validator
    validator = validator_cls(schema)
    errors = sorted(validator.iter_errors(instance), key=lambda e: list(e.path))

    if errors:
        messages = []
        for err in errors:
            path = ".".join(str(p) for p in err.absolute_path) if err.path else "<root>"
            messages.append(f"  [{path}] {err.message}")

        raise ToolSchemaValidationError(
            f"Tool {context} schema validation failed "
            f"({len(errors)} error{'s' if len(errors) > 1 else ''}):\n"
            + "\n".join(messages),
            errors=messages,
            schema=schema,
            instance=instance,
        )
