"""Jupyter magic commands for AgentBible.

Provides IPython/Jupyter integration for interactive validation and settings.

Usage:
    %load_ext agentbible.jupyter

    %agentbible level debug
    %agentbible info

    %%validate unitarity
    result = create_hadamard()

Author: Generated by AgentBible
"""

from __future__ import annotations

import os
from typing import Any

# Try to import IPython - will fail gracefully if not in notebook environment
try:
    from IPython import get_ipython
    from IPython.core.magic import Magics, cell_magic, line_magic, magics_class
    from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring

    IPYTHON_AVAILABLE = True
except ImportError:
    IPYTHON_AVAILABLE = False
    # Define dummy classes for type checking
    Magics = object  # type: ignore[misc, assignment]

    def magics_class(cls: Any) -> Any:  # type: ignore[misc]
        return cls

    def line_magic(func: Any) -> Any:  # type: ignore[misc]
        return func

    def cell_magic(func: Any) -> Any:  # type: ignore[misc]
        return func

    def magic_arguments() -> Any:  # type: ignore[misc]
        def decorator(func: Any) -> Any:
            return func

        return decorator

    def argument(*args: Any, **kwargs: Any) -> Any:  # type: ignore[misc]
        def decorator(func: Any) -> Any:
            return func

        return decorator

    def parse_argstring(func: Any, line: str) -> Any:  # type: ignore[misc]
        return None

    def get_ipython() -> None:  # type: ignore[misc]
        return None


ENV_VALIDATION_LEVEL = "AGENTBIBLE_VALIDATION_LEVEL"


@magics_class
class AgentBibleMagics(Magics):  # type: ignore[misc]
    """AgentBible Jupyter magic commands.

    Provides interactive control over validation levels and
    quick validation of cell outputs.
    """

    @line_magic
    def agentbible(self, line: str) -> None:
        """Line magic for AgentBible settings.

        Usage:
            %agentbible level debug   # Set validation level
            %agentbible level lite    # Fast validation
            %agentbible level off     # Disable validation
            %agentbible info          # Show current settings
            %agentbible help          # Show help
        """
        args = line.strip().split()

        if not args:
            self._show_help()
            return

        cmd = args[0].lower()

        if cmd == "level" and len(args) > 1:
            self._set_level(args[1])
        elif cmd == "info":
            self._show_info()
        elif cmd == "help":
            self._show_help()
        else:
            print(f"Unknown command: {cmd}")
            self._show_help()

    def _set_level(self, level: str) -> None:
        """Set the validation level."""
        valid_levels = ["debug", "lite", "off"]
        if level.lower() not in valid_levels:
            print(f"Invalid level: {level}")
            print(f"Valid levels: {', '.join(valid_levels)}")
            return

        os.environ[ENV_VALIDATION_LEVEL] = level.lower()
        print(f"Validation level set to: {level.lower()}")

        if level.lower() == "off":
            print("⚠️  Warning: All validation is disabled!")
        elif level.lower() == "lite":
            print("ℹ️  Only NaN/Inf checks will run (fast mode)")

    def _show_info(self) -> None:
        """Show AgentBible information."""
        try:
            from agentbible import __version__

            version = __version__
        except ImportError:
            version = "unknown"

        level = os.environ.get(ENV_VALIDATION_LEVEL, "debug")

        print(f"AgentBible v{version}")
        print(f"Validation level: {level}")
        print()
        print("Environment variable:")
        print(f"  {ENV_VALIDATION_LEVEL} = {level}")

    def _show_help(self) -> None:
        """Show help message."""
        print("AgentBible Jupyter Magic Commands")
        print()
        print("Usage:")
        print("  %agentbible level <level>  - Set validation level")
        print("  %agentbible info           - Show current settings")
        print("  %agentbible help           - Show this help")
        print()
        print("Validation Levels:")
        print("  debug - Full physics validation (default)")
        print("  lite  - Only NaN/Inf checks (fast)")
        print("  off   - Disable all validation")
        print()
        print("Cell Magic:")
        print("  %%validate <check>")
        print("  <code that produces result>")

    @cell_magic
    @magic_arguments()
    @argument(
        "check",
        type=str,
        nargs="?",
        default="all",
        help="Validation check: unitarity, hermitian, normalized, density, all",
    )
    def validate(self, line: str, cell: str) -> Any:
        """Cell magic to validate the cell output.

        Usage:
            %%validate unitarity
            result = create_hadamard()
            result  # Last expression is validated

            %%validate normalized
            psi = prepare_state()
            psi

            %%validate all
            rho = create_density_matrix()
            rho
        """
        check_type = line.strip() or "all"

        # Execute the cell and capture the result
        result = self.shell.run_cell(cell)  # type: ignore[attr-defined]

        if result.error_in_exec:
            return result

        # Get the result value
        output = result.result
        if output is None:
            print("No result to validate")
            return result

        # Run validation based on check type
        self._run_validation(output, check_type)

        return result

    def _run_validation(self, data: Any, check_type: str) -> None:
        """Run the specified validation on data."""
        import numpy as np

        if not isinstance(data, np.ndarray):
            print(f"⚠️  Cannot validate non-array type: {type(data).__name__}")
            return

        checks_passed = []
        checks_failed = []

        try:
            from agentbible.validators import check_finite

            check_finite(data)
            checks_passed.append("no_nan_inf")
        except (ImportError, ValueError) as e:
            if "NaN" in str(e) or "Inf" in str(e):
                checks_failed.append(("no_nan_inf", str(e)))

        if check_type in ("unitarity", "all") and data.ndim == 2:
            try:
                from agentbible.validators.quantum import check_unitarity

                check_unitarity(data)
                checks_passed.append("unitarity")
            except ImportError:
                pass  # Quantum validators not installed
            except ValueError as e:
                checks_failed.append(("unitarity", str(e)))

        if check_type in ("hermitian", "all") and data.ndim == 2:
            try:
                from agentbible.validators.quantum import check_hermitian

                check_hermitian(data)
                checks_passed.append("hermitian")
            except ImportError:
                pass
            except ValueError as e:
                checks_failed.append(("hermitian", str(e)))

        if check_type in ("normalized", "all") and data.ndim == 1:
            try:
                from agentbible.validators.quantum import check_normalized

                check_normalized(data)
                checks_passed.append("normalized")
            except ImportError:
                pass
            except ValueError as e:
                checks_failed.append(("normalized", str(e)))

        if check_type in ("density", "all") and data.ndim == 2:
            try:
                from agentbible.validators.quantum import check_density_matrix

                check_density_matrix(data)
                checks_passed.append("density_matrix")
            except ImportError:
                pass
            except ValueError as e:
                checks_failed.append(("density_matrix", str(e)))

        # Report results
        if checks_passed:
            print(f"✓ Passed: {', '.join(checks_passed)}")
        if checks_failed:
            for check_name, error in checks_failed:
                print(f"✗ Failed {check_name}: {error}")


def load_ipython_extension(ipython: Any) -> None:
    """Register AgentBible magics with IPython.

    Called when user runs: %load_ext agentbible.jupyter
    """
    if not IPYTHON_AVAILABLE:
        print("IPython is not available. Magic commands require Jupyter/IPython.")
        return

    ipython.register_magics(AgentBibleMagics)
    print("AgentBible magics loaded. Use %agentbible help for usage.")


def unload_ipython_extension(ipython: Any) -> None:
    """Unload the extension."""
    pass  # Nothing to clean up


# Auto-load when module is imported in IPython context
def _auto_load() -> None:
    """Auto-load magics if running in IPython."""
    if IPYTHON_AVAILABLE:
        ip = get_ipython()
        if ip is not None:
            load_ipython_extension(ip)


# Only auto-load if explicitly imported (not during package init)
# Users should use %load_ext agentbible.jupyter
