"""Validator for Agent Trajectory Interchange Format (ATIF) trajectories.

This module provides validation functionality for trajectory files following
the ATIF specification (RFC 0001).
"""

from typing import Any, Dict, List, Union
import json
from pathlib import Path

from pydantic import ValidationError

from harbor.models.trajectories import Trajectory


class TrajectoryValidator:
    """Validator for ATIF trajectory format.

    Validates that trajectory JSON follows the schema defined in RFC 0001,
    using Pydantic models for validation.

    Always collects all validation errors before returning.
    """

    def __init__(self):
        """Initialize the validator."""
        self.errors: List[str] = []

    def _add_error(self, error: str) -> None:
        """Add an error to the error list.

        Args:
            error: Error message to add.
        """
        self.errors.append(error)

    def validate(self, trajectory: Union[Dict[str, Any], str, Path]) -> bool:
        """Validate a complete trajectory.

        Args:
            trajectory: Trajectory to validate. Can be a dict, JSON string,
                       or path to a JSON file.

        Returns:
            True if valid, False otherwise. All errors are collected in self.errors.
        """
        self.errors = []

        # Load trajectory if it's a string or path
        if isinstance(trajectory, (str, Path)):
            path = Path(trajectory)
            if path.exists():
                with open(path, "r") as f:
                    try:
                        trajectory = json.load(f)
                    except json.JSONDecodeError as e:
                        self._add_error(f"Invalid JSON: {e}")
                        return False
            else:
                try:
                    trajectory = json.loads(str(trajectory))
                except json.JSONDecodeError as e:
                    if isinstance(trajectory, Path):
                        self._add_error(f"File not found: {trajectory}")
                    else:
                        self._add_error(
                            f"Input string is not a valid file path and not valid JSON: {e}"
                        )
                    return False

        if not isinstance(trajectory, dict):
            self._add_error("Trajectory must be a JSON object/dict")
            return False

        # Use Pydantic for validation
        try:
            Trajectory(**trajectory)
            return True
        except ValidationError as e:
            # Convert Pydantic errors to our error format
            for error in e.errors():
                loc_str = ".".join(str(x) for x in error["loc"])
                msg = error["msg"]
                error_type = error["type"]
                error_input = error.get("input")

                # Format the error message in a user-friendly way
                if error_type == "missing":
                    self._add_error(f"trajectory.{loc_str}: required field is missing")
                elif error_type == "extra_forbidden":
                    self._add_error(f"trajectory.{loc_str}: unexpected field (not part of ATIF schema)")
                elif error_type.startswith("value_error"):
                    # Custom validation error from our validators
                    self._add_error(f"trajectory.{loc_str}: {msg}")
                elif error_type.startswith("type_error") or error_type in ["string_type", "int_type", "float_type", "dict_type", "list_type"]:
                    # Type mismatch error
                    # Include the actual value in the error message for better debugging
                    if error_input is not None:
                        self._add_error(f"trajectory.{loc_str}: expected {error_type.replace('_', ' ')}, got {type(error_input).__name__}")
                    else:
                        self._add_error(f"trajectory.{loc_str}: {msg}")
                elif error_type == "literal_error":
                    # Literal/enum validation failed - include the actual invalid value
                    if error_input is not None:
                        self._add_error(f"trajectory.{loc_str}: {msg}, got '{error_input}'")
                    else:
                        self._add_error(f"trajectory.{loc_str}: {msg}")
                else:
                    # Generic error
                    self._add_error(f"trajectory.{loc_str}: {msg}")

            return False

    def get_errors(self) -> List[str]:
        """Get all validation errors.

        Returns:
            List of error messages.
        """
        return self.errors


def validate_trajectory(trajectory: Union[Dict[str, Any], str, Path]) -> bool:
    """Validate a trajectory against the ATIF schema.

    Args:
        trajectory: Trajectory to validate (dict, JSON string, or file path).

    Returns:
        True if valid, False otherwise.
    """
    validator = TrajectoryValidator()
    return validator.validate(trajectory)


def main():
    """CLI entrypoint for trajectory validation."""
    import argparse
    import sys

    parser = argparse.ArgumentParser(
        description="Validate Agent Trajectory Interchange Format (ATIF) trajectory files"
    )
    parser.add_argument(
        "trajectory_file",
        type=str,
        help="Path to the trajectory JSON file to validate",
    )

    args = parser.parse_args()

    trajectory_path = Path(args.trajectory_file)

    if not trajectory_path.exists():
        print(f"Error: File not found: {trajectory_path}", file=sys.stderr)
        sys.exit(1)

    validator = TrajectoryValidator()

    try:
        is_valid = validator.validate(trajectory_path)

        if is_valid:
            print(f"✓ Trajectory is valid: {trajectory_path}")
            sys.exit(0)
        else:
            print(f"✗ Trajectory validation failed: {trajectory_path}", file=sys.stderr)
            print(f"\nFound {len(validator.errors)} error(s):", file=sys.stderr)
            for error in validator.errors:
                print(f"  - {error}", file=sys.stderr)
            sys.exit(1)

    except Exception as e:
        print(f"✗ Validation error: {e}", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()
