"""SchemaCheck: Validate output against a JSON schema."""

from __future__ import annotations

import json
from typing import Any

from jsonschema import ValidationError, validate

from ai_qa.checks.registry import register
from ai_qa.core.check import BaseCheck
from ai_qa.core.context import Context
from ai_qa.core.result import CheckResult
from ai_qa.exceptions import ContextValidationError


@register("schema")
class SchemaCheck(BaseCheck):
    """Validate output against a JSON schema.

    Requires:
        - ctx.output: valid JSON string or dict/list
        - schema: JSON schema dict (passed via config)

    Example:
        schema = {
            "type": "object",
            "properties": {
                "name": {"type": "string"},
                "age": {"type": "integer"}
            },
            "required": ["name"]
        }
        check = SchemaCheck(schema=schema)
    """

    requires_llm = False
    version = "1.0.0"
    description = "Validate output against a JSON schema"

    def __init__(
        self,
        threshold: float = 0.5,
        schema: dict[str, Any] | None = None,
        **kwargs: Any,
    ) -> None:
        """Initialize SchemaCheck.

        Args:
            threshold: Score threshold (0.0-1.0).
            schema: JSON schema to validate against.
            **kwargs: Additional config kwargs.

        Raises:
            ValueError: If schema is missing.
        """
        super().__init__(threshold=threshold, **kwargs)
        if schema is None:
            raise ValueError(
                "SchemaCheck requires a 'schema' parameter.\n"
                "Example: SchemaCheck(schema={'type': 'object', 'properties': {...}})"
            )
        self.schema = schema

    def validate_context(self, ctx: Context) -> None:
        """Validate that output exists and is provided.

        Args:
            ctx: Context to validate.

        Raises:
            ContextValidationError: If output is missing.
        """
        if ctx.output is None:
            raise ContextValidationError(
                "SchemaCheck requires ctx.output to be set.\n"
                "Example: Context(output={'name': 'John', 'age': 30})"
            )

    def evaluate(self, ctx: Context) -> CheckResult:
        """Evaluate output against schema.

        Args:
            ctx: Context with output to validate.

        Returns:
            CheckResult with pass/fail and evidence.
        """
        self.validate_context(ctx)

        # Convert output to dict/list if it's a JSON string
        output = ctx.output
        if isinstance(output, str):
            try:
                output = json.loads(output)
            except json.JSONDecodeError as e:
                return CheckResult(
                    name=self.name,
                    passed=False,
                    score=0.0,
                    threshold=self.threshold,
                    evidence=f"Output is not valid JSON: {str(e)}",
                    check_version=self.version,
                )

        # Validate against schema
        try:
            validate(instance=output, schema=self.schema)
            return CheckResult(
                name=self.name,
                passed=True,
                score=1.0,
                threshold=self.threshold,
                evidence="Output matches schema",
                check_version=self.version,
            )
        except ValidationError as e:
            return CheckResult(
                name=self.name,
                passed=False,
                score=0.0,
                threshold=self.threshold,
                evidence=f"Schema validation failed: {e.message}",
                check_version=self.version,
            )
