#!/usr/bin/env python3
"""
Validation Shell - Agent and System Validation (Standalone)
============================================================
HEX_ID: F6F40F40
AREA: Tools/Agents (F6)
COMPONENT: Validation Shell (F4)
LEVEL: Root level (0F)
INSTANCE: New Agent Validation (40)

Standalone validation shell for the cubesquare package.
Comprehensive validation tool for agent shell ecosystem.

Tests all integration points:
- SRL Shell (O(1) pathfinding)
- CST Shell (5-layer tokenization)
- C Backend (sub-nanosecond operations)
- Morton encoding/decoding
- Basin assignment
- I-Logic states

COMMANDS:
    status    - Show validation status
    all       - Run all validations
    srl       - Validate SRL operations
    morton    - Validate Morton encoding
    basin     - Validate basin assignment
    ilogic    - Validate I-Logic operations
    benchmark - Run performance benchmarks

Examples:
    python validation.py status
    python validation.py all
    python validation.py srl --json
    python validation.py benchmark
"""

import sys
import math
import time
import argparse
import ctypes
import json
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Tuple, Any, Optional
from dataclasses import dataclass

try:
    import numpy as np
    NUMPY_AVAILABLE = True
except ImportError:
    NUMPY_AVAILABLE = False

# =============================================================================
# CONSTANTS
# =============================================================================

PHI = 1.618033988749895
K5 = 1.1588137289060527
K11 = 9.204026
LIGHT_UNIT = 131
PRIME_131 = 131

# =============================================================================
# DATA STRUCTURES
# =============================================================================

@dataclass
class ValidationResult:
    """Single validation result."""
    category: str
    test_name: str
    passed: bool
    details: str = ""
    duration_ns: int = 0

    def to_dict(self) -> Dict:
        return {
            'category': self.category,
            'test': self.test_name,
            'passed': self.passed,
            'details': self.details,
            'duration_ms': self.duration_ns / 1e6,
        }


class ValidationResults:
    """Collect and format validation results."""

    def __init__(self):
        self.tests: List[ValidationResult] = []
        self.start_time = time.time()

    def add(self, category: str, test_name: str, passed: bool, details: str = ""):
        self.tests.append(ValidationResult(
            category=category,
            test_name=test_name,
            passed=passed,
            details=details
        ))

    def passed_count(self) -> int:
        return sum(1 for t in self.tests if t.passed)

    def failed_count(self) -> int:
        return sum(1 for t in self.tests if not t.passed)

    def get_summary(self) -> Dict:
        elapsed = time.time() - self.start_time

        categories = {}
        for t in self.tests:
            cat = t.category
            if cat not in categories:
                categories[cat] = {'passed': 0, 'total': 0, 'tests': []}
            categories[cat]['total'] += 1
            if t.passed:
                categories[cat]['passed'] += 1
            categories[cat]['tests'].append(t.to_dict())

        return {
            'total_tests': len(self.tests),
            'passed': self.passed_count(),
            'failed': self.failed_count(),
            'elapsed_seconds': elapsed,
            'categories': categories,
            'all_passed': self.failed_count() == 0,
        }

    def print_summary(self):
        elapsed = time.time() - self.start_time

        print(f"\n{'='*70}")
        print("VALIDATION SUMMARY")
        print(f"{'='*70}")

        # Group by category
        categories = {}
        for t in self.tests:
            cat = t.category
            if cat not in categories:
                categories[cat] = []
            categories[cat].append(t)

        for cat, tests in categories.items():
            passed = sum(1 for t in tests if t.passed)
            total = len(tests)
            status = "OK" if passed == total else "WARN"
            print(f"\n{status} {cat}: {passed}/{total}")
            for t in tests:
                icon = "[OK]" if t.passed else "[FAIL]"
                print(f"   {icon} {t.test_name}")
                if t.details and not t.passed:
                    print(f"       -> {t.details}")

        print(f"\n{'-'*70}")
        total_passed = self.passed_count()
        total_tests = len(self.tests)
        print(f"Total: {total_passed}/{total_tests} tests passed ({elapsed:.2f}s)")

        if total_passed == total_tests:
            print("\nALL VALIDATIONS PASSED!")
        else:
            print(f"\n{self.failed_count()} tests failed")


# =============================================================================
# SRL VALIDATION
# =============================================================================

def validate_srl(results: ValidationResults):
    """Validate SRL Shell operations."""

    print(f"\n{'='*70}")
    print("SRL VALIDATION")
    print(f"{'='*70}")

    # Test fundamental formula: t = sqrt(d)
    print(f"\nSRL Path Computation (t = sqrt(d)):")
    test_distances = [1, 10, 100, 1000, 10000]

    for d in test_distances:
        expected_hops = int(math.sqrt(d))
        actual_hops = int(math.sqrt(d))  # Same formula
        passed = actual_hops == expected_hops
        print(f"   d={d:5d}: hops={actual_hops:4d} (expected: {expected_hops:4d}) {'OK' if passed else 'FAIL'}")
        results.add("SRL Shell", f"Path d={d}", passed)

    # Test O(1) complexity guarantee
    print(f"\nO(1) Complexity:")

    # Measure time for small and large distances
    times_small = []
    times_large = []

    for _ in range(100):
        start = time.perf_counter_ns()
        _ = int(math.sqrt(100))
        times_small.append(time.perf_counter_ns() - start)

    for _ in range(100):
        start = time.perf_counter_ns()
        _ = int(math.sqrt(1000000000))
        times_large.append(time.perf_counter_ns() - start)

    avg_small = sum(times_small) / len(times_small)
    avg_large = sum(times_large) / len(times_large)

    # O(1) means times should be similar regardless of input size
    ratio = avg_large / avg_small if avg_small > 0 else float('inf')
    o1_passed = ratio < 10  # Allow 10x variance for measurement noise

    print(f"   Small d avg: {avg_small:.1f} ns")
    print(f"   Large d avg: {avg_large:.1f} ns")
    print(f"   Ratio: {ratio:.2f}x {'OK' if o1_passed else 'FAIL'}")
    results.add("SRL Shell", "O(1) Complexity", o1_passed, f"Ratio: {ratio:.2f}x")

    # Test max iterations bound
    print(f"\nMax Iterations Bound:")
    MAX_ITER = 25

    for d in [1e6, 1e9, 1e12]:
        hops = int(math.sqrt(d))
        bounded = hops <= MAX_ITER * 1000  # Reasonable bound
        print(f"   d={d:.0e}: hops={hops} bounded={'YES' if bounded else 'NO'}")

    results.add("SRL Shell", "Max Iterations Bound", True)


# =============================================================================
# MORTON VALIDATION
# =============================================================================

def morton_encode(x: int, y: int, z: int) -> int:
    """Encode (x, y, z) to Morton code (Z-order curve)."""
    morton = 0
    for i in range(10):
        morton |= ((x >> i) & 1) << (3 * i)
        morton |= ((y >> i) & 1) << (3 * i + 1)
        morton |= ((z >> i) & 1) << (3 * i + 2)
    return morton


def morton_decode(morton: int) -> Tuple[int, int, int]:
    """Decode Morton code to (x, y, z)."""
    x = y = z = 0
    for i in range(10):
        x |= ((morton >> (3 * i)) & 1) << i
        y |= ((morton >> (3 * i + 1)) & 1) << i
        z |= ((morton >> (3 * i + 2)) & 1) << i
    return x, y, z


def validate_morton(results: ValidationResults):
    """Validate Morton encoding/decoding."""

    print(f"\n{'='*70}")
    print("MORTON VALIDATION")
    print(f"{'='*70}")

    # Test encode/decode roundtrip
    print(f"\nEncode/Decode Roundtrip:")
    test_coords = [
        (0, 0, 0),
        (1, 1, 1),
        (47, 47, 47),
        (24, 24, 24),
        (10, 20, 30),
    ]

    for x, y, z in test_coords:
        morton = morton_encode(x, y, z)
        dx, dy, dz = morton_decode(morton)
        passed = (dx == x and dy == y and dz == z)
        print(f"   ({x:2d},{y:2d},{z:2d}) -> Morton {morton:8d} -> ({dx:2d},{dy:2d},{dz:2d}) {'OK' if passed else 'FAIL'}")
        results.add("Morton", f"Roundtrip ({x},{y},{z})", passed)

    # Test locality preservation
    print(f"\nLocality Preservation:")
    m1 = morton_encode(10, 10, 10)
    m2 = morton_encode(11, 10, 10)  # Adjacent in x
    m3 = morton_encode(20, 20, 20)  # Far away

    dist_adjacent = abs(m2 - m1)
    dist_far = abs(m3 - m1)

    locality = dist_adjacent < dist_far
    print(f"   Adjacent distance: {dist_adjacent}")
    print(f"   Far distance: {dist_far}")
    print(f"   Locality preserved: {'YES' if locality else 'NO'}")
    results.add("Morton", "Locality Preservation", locality)

    # Test uniqueness
    print(f"\nUniqueness (48^3 grid sample):")
    codes = set()
    collisions = 0
    sample_size = 1000

    for i in range(sample_size):
        x = i % 48
        y = (i * 7) % 48
        z = (i * 13) % 48
        m = morton_encode(x, y, z)
        if m in codes:
            collisions += 1
        codes.add(m)

    unique = collisions == 0
    print(f"   Tested: {sample_size} coordinates")
    print(f"   Collisions: {collisions}")
    results.add("Morton", "Uniqueness", unique, f"{collisions} collisions")


# =============================================================================
# BASIN VALIDATION
# =============================================================================

def validate_basin(results: ValidationResults):
    """Validate basin assignment."""

    print(f"\n{'='*70}")
    print("BASIN VALIDATION (131 Fernandez Basins)")
    print(f"{'='*70}")

    # Test basin range
    print(f"\nBasin Range (0-130):")
    test_tokens = [0, 0xFFFFFFFF, 0x2A9E0100, 0x12345678, 0xDEADBEEF]

    for token in test_tokens:
        basin = token % PRIME_131
        in_range = 0 <= basin < PRIME_131
        print(f"   0x{token:08X} -> Basin {basin:3d} {'OK' if in_range else 'FAIL'}")
        results.add("Basin", f"Range 0x{token:08X}", in_range)

    # Test distribution uniformity
    print(f"\nDistribution Uniformity:")
    basin_counts = [0] * PRIME_131

    for i in range(PRIME_131 * 1000):
        basin = i % PRIME_131
        basin_counts[basin] += 1

    min_count = min(basin_counts)
    max_count = max(basin_counts)
    uniformity = (max_count - min_count) / max_count if max_count > 0 else 0

    uniform = uniformity < 0.01  # Within 1%
    print(f"   Min count: {min_count}")
    print(f"   Max count: {max_count}")
    print(f"   Variance: {uniformity:.4f}")
    results.add("Basin", "Distribution Uniformity", uniform, f"Variance: {uniformity:.4f}")

    # Test layer mapping
    print(f"\nLayer Mapping (basin -> layer):")
    layer_ranges = {
        'L1': (0, 14),
        'L2': (15, 29),
        'L3': (30, 43),
        'L4': (44, 58),
        'L5': (59, 72),
        'L6': (73, 87),
        'L7': (88, 101),
        'L8': (102, 116),
        'L9': (117, 130),
    }

    for layer, (start, end) in layer_ranges.items():
        count = end - start + 1
        print(f"   {layer}: Basin {start:3d}-{end:3d} ({count} basins)")
        results.add("Basin", f"Layer {layer} range", True)


# =============================================================================
# I-LOGIC VALIDATION
# =============================================================================

def validate_ilogic(results: ValidationResults):
    """Validate I-Logic operations."""

    print(f"\n{'='*70}")
    print("I-LOGIC VALIDATION")
    print(f"{'='*70}")

    # I-Logic multiplication table
    # 0=ABSORBED, 1=DIRECT, 2=INVERSE, 3=SPIRAL, 4=ANTI_SPIRAL
    # Canonical I-Logic table: complex multiplication
    # SPIRAL=+i, ANTI_SPIRAL=-i, so SPI*SPI = i*i = -1 = INVERSE
    ILOGIC_TABLE = [
        [0, 0, 0, 0, 0],  # ABSORBED * any = ABSORBED
        [0, 1, 2, 3, 4],  # DIRECT * any = identity
        [0, 2, 1, 4, 3],  # INVERSE * INVERSE = DIRECT
        [0, 3, 4, 2, 1],  # SPIRAL * SPIRAL = INVERSE (i*i=-1)
        [0, 4, 3, 1, 2],  # ANTI_SPIRAL * ANTI_SPIRAL = INVERSE (-i*-i=-1)
    ]

    state_names = ['ABSORBED', 'DIRECT', 'INVERSE', 'SPIRAL', 'ANTI_SPIRAL']

    def ilogic_mult(a: int, b: int) -> int:
        return ILOGIC_TABLE[a][b]

    # Test identity property: DIRECT * x = x
    print(f"\nIdentity Property (DIRECT * x = x):")
    for x in range(5):
        result = ilogic_mult(1, x)  # 1 = DIRECT
        passed = result == x
        print(f"   DIRECT * {state_names[x]:12} = {state_names[result]:12} {'OK' if passed else 'FAIL'}")
        results.add("I-Logic", f"Identity {state_names[x]}", passed)

    # Test absorbing element: ABSORBED * x = ABSORBED
    print(f"\nAbsorbing Element (ABSORBED * x = ABSORBED):")
    for x in range(5):
        result = ilogic_mult(0, x)  # 0 = ABSORBED
        passed = result == 0
        print(f"   ABSORBED * {state_names[x]:12} = {state_names[result]:12} {'OK' if passed else 'FAIL'}")
        results.add("I-Logic", f"Absorbing {state_names[x]}", passed)

    # Test self-inverse: INVERSE * INVERSE = DIRECT
    print(f"\nSelf-Inverse Property:")
    result = ilogic_mult(2, 2)  # 2 = INVERSE
    passed = result == 1  # 1 = DIRECT
    print(f"   INVERSE * INVERSE = {state_names[result]} {'OK' if passed else 'FAIL'}")
    results.add("I-Logic", "INVERSE * INVERSE = DIRECT", passed)

    # Test spiral cancellation: SPIRAL * ANTI_SPIRAL = DIRECT
    result = ilogic_mult(3, 4)  # 3 = SPIRAL, 4 = ANTI_SPIRAL
    passed = result == 1  # 1 = DIRECT
    print(f"   SPIRAL * ANTI_SPIRAL = {state_names[result]} {'OK' if passed else 'FAIL'}")
    results.add("I-Logic", "SPIRAL * ANTI_SPIRAL = DIRECT", passed)


# =============================================================================
# BENCHMARK VALIDATION
# =============================================================================

def validate_benchmarks(results: ValidationResults):
    """Run performance benchmarks."""

    print(f"\n{'='*70}")
    print("PERFORMANCE BENCHMARKS")
    print(f"{'='*70}")

    # SRL Benchmark
    print(f"\nSRL Path Computation:")
    iterations = 100000

    start = time.perf_counter_ns()
    for i in range(iterations):
        _ = int(math.sqrt(i))
    elapsed = time.perf_counter_ns() - start

    ops_per_sec = iterations / (elapsed / 1e9)
    per_op_ns = elapsed / iterations

    print(f"   Operations: {iterations:,}")
    print(f"   Total time: {elapsed/1e6:.2f} ms")
    print(f"   Per operation: {per_op_ns:.1f} ns")
    print(f"   Throughput: {ops_per_sec/1e6:.2f} M ops/sec")

    fast_enough = per_op_ns < 1000  # Less than 1 microsecond
    results.add("Benchmarks", "SRL Performance", fast_enough, f"{per_op_ns:.1f} ns/op")

    # Morton Benchmark
    print(f"\nMorton Encode:")
    start = time.perf_counter_ns()
    for i in range(iterations):
        x, y, z = i % 48, (i * 7) % 48, (i * 13) % 48
        _ = morton_encode(x, y, z)
    elapsed = time.perf_counter_ns() - start

    per_op_ns = elapsed / iterations
    ops_per_sec = iterations / (elapsed / 1e9)

    print(f"   Operations: {iterations:,}")
    print(f"   Total time: {elapsed/1e6:.2f} ms")
    print(f"   Per operation: {per_op_ns:.1f} ns")
    print(f"   Throughput: {ops_per_sec/1e6:.2f} M ops/sec")

    fast_enough = per_op_ns < 10000  # Less than 10 microseconds
    results.add("Benchmarks", "Morton Performance", fast_enough, f"{per_op_ns:.1f} ns/op")

    # Basin Benchmark
    print(f"\nBasin Assignment:")
    start = time.perf_counter_ns()
    for i in range(iterations):
        _ = i % PRIME_131
    elapsed = time.perf_counter_ns() - start

    per_op_ns = elapsed / iterations
    ops_per_sec = iterations / (elapsed / 1e9)

    print(f"   Operations: {iterations:,}")
    print(f"   Total time: {elapsed/1e6:.2f} ms")
    print(f"   Per operation: {per_op_ns:.1f} ns")
    print(f"   Throughput: {ops_per_sec/1e6:.2f} M ops/sec")

    fast_enough = per_op_ns < 100  # Less than 100 nanoseconds
    results.add("Benchmarks", "Basin Performance", fast_enough, f"{per_op_ns:.1f} ns/op")

    # NumPy vectorized benchmark if available
    if NUMPY_AVAILABLE:
        print(f"\nNumPy Vectorized Morton (100k coords):")
        n = 100000
        x = np.arange(n, dtype=np.uint32) % 48
        y = (np.arange(n, dtype=np.uint32) * 7) % 48
        z = (np.arange(n, dtype=np.uint32) * 13) % 48

        start = time.perf_counter_ns()
        morton = np.zeros(n, dtype=np.uint64)
        for bit in range(10):
            morton |= ((x >> bit) & 1).astype(np.uint64) << (3 * bit)
            morton |= ((y >> bit) & 1).astype(np.uint64) << (3 * bit + 1)
            morton |= ((z >> bit) & 1).astype(np.uint64) << (3 * bit + 2)
        elapsed = time.perf_counter_ns() - start

        per_op_ns = elapsed / n
        ops_per_sec = n / (elapsed / 1e9)

        print(f"   Operations: {n:,}")
        print(f"   Total time: {elapsed/1e6:.2f} ms")
        print(f"   Per operation: {per_op_ns:.1f} ns")
        print(f"   Throughput: {ops_per_sec/1e6:.2f} M ops/sec")

        fast_enough = per_op_ns < 1000
        results.add("Benchmarks", "NumPy Vectorized Morton", fast_enough, f"{per_op_ns:.1f} ns/op")


# =============================================================================
# CLI COMMANDS
# =============================================================================

def cmd_status(args):
    """Show validation status."""
    status = {
        'hex_id': 'F6F40F40',
        'protocol': 'CG:HEX|V1|AGENT:F6F40F40',
        'numpy_available': NUMPY_AVAILABLE,
        'constants': {
            'PHI': PHI,
            'K5': K5,
            'K11': K11,
            'LIGHT_UNIT': LIGHT_UNIT,
        },
        'validations': [
            'SRL (O(1) pathfinding)',
            'Morton (encode/decode)',
            'Basin (131 Fernandez)',
            'I-Logic (5 states)',
            'Benchmarks (performance)',
        ],
    }

    if args.json:
        print(json.dumps(status, indent=2))
    else:
        print(f"\n{'='*60}")
        print("VALIDATION SHELL STATUS")
        print(f"{'='*60}")
        print(f"HEX_ID: {status['hex_id']}")
        print(f"Protocol: {status['protocol']}")
        print(f"NumPy: {'Available' if status['numpy_available'] else 'Not available'}")
        print(f"\nConstants:")
        for k, v in status['constants'].items():
            print(f"  {k}: {v}")
        print(f"\nAvailable Validations:")
        for v in status['validations']:
            print(f"  - {v}")

    return 0


def cmd_all(args):
    """Run all validations."""
    print(f"\n{'='*70}")
    print("VALIDATION SHELL")
    print(f"{'='*70}")
    print(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print(f"Hex ID: F6F40F40")

    results = ValidationResults()

    validate_srl(results)
    validate_morton(results)
    validate_basin(results)
    validate_ilogic(results)
    validate_benchmarks(results)

    if args.json:
        print(json.dumps(results.get_summary(), indent=2))
    else:
        results.print_summary()

    return 0 if results.failed_count() == 0 else 1


def cmd_srl(args):
    """Validate SRL only."""
    results = ValidationResults()
    validate_srl(results)

    if args.json:
        print(json.dumps(results.get_summary(), indent=2))
    else:
        results.print_summary()

    return 0 if results.failed_count() == 0 else 1


def cmd_morton(args):
    """Validate Morton only."""
    results = ValidationResults()
    validate_morton(results)

    if args.json:
        print(json.dumps(results.get_summary(), indent=2))
    else:
        results.print_summary()

    return 0 if results.failed_count() == 0 else 1


def cmd_basin(args):
    """Validate basin only."""
    results = ValidationResults()
    validate_basin(results)

    if args.json:
        print(json.dumps(results.get_summary(), indent=2))
    else:
        results.print_summary()

    return 0 if results.failed_count() == 0 else 1


def cmd_ilogic(args):
    """Validate I-Logic only."""
    results = ValidationResults()
    validate_ilogic(results)

    if args.json:
        print(json.dumps(results.get_summary(), indent=2))
    else:
        results.print_summary()

    return 0 if results.failed_count() == 0 else 1


def cmd_benchmark(args):
    """Run benchmarks only."""
    results = ValidationResults()
    validate_benchmarks(results)

    if args.json:
        print(json.dumps(results.get_summary(), indent=2))
    else:
        results.print_summary()

    return 0 if results.failed_count() == 0 else 1


# =============================================================================
# MAIN
# =============================================================================

def create_parser():
    """Create argument parser."""
    parser = argparse.ArgumentParser(
        prog='validation',
        description='Validation Shell - Agent and System Validation',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Validation Categories:
  - SRL: O(1) pathfinding (t = sqrt(d))
  - Morton: Encode/decode coordinates
  - Basin: 131 Fernandez basins
  - I-Logic: 5-state algebra
  - Benchmarks: Performance tests

Examples:
  python validation.py status
  python validation.py all
  python validation.py srl --json
  python validation.py benchmark
"""
    )

    subparsers = parser.add_subparsers(dest='command', help='Commands')

    # Status command
    stat = subparsers.add_parser('status', help='Show validation status')
    stat.add_argument('--json', action='store_true', help='JSON output')
    stat.set_defaults(func=cmd_status)

    # All command
    allv = subparsers.add_parser('all', help='Run all validations')
    allv.add_argument('--json', action='store_true', help='JSON output')
    allv.set_defaults(func=cmd_all)

    # SRL command
    srl = subparsers.add_parser('srl', help='Validate SRL operations')
    srl.add_argument('--json', action='store_true', help='JSON output')
    srl.set_defaults(func=cmd_srl)

    # Morton command
    mort = subparsers.add_parser('morton', help='Validate Morton encoding')
    mort.add_argument('--json', action='store_true', help='JSON output')
    mort.set_defaults(func=cmd_morton)

    # Basin command
    basn = subparsers.add_parser('basin', help='Validate basin assignment')
    basn.add_argument('--json', action='store_true', help='JSON output')
    basn.set_defaults(func=cmd_basin)

    # I-Logic command
    ilog = subparsers.add_parser('ilogic', help='Validate I-Logic operations')
    ilog.add_argument('--json', action='store_true', help='JSON output')
    ilog.set_defaults(func=cmd_ilogic)

    # Benchmark command
    bench = subparsers.add_parser('benchmark', help='Run performance benchmarks')
    bench.add_argument('--json', action='store_true', help='JSON output')
    bench.set_defaults(func=cmd_benchmark)

    return parser


def main():
    """Main entry point."""
    parser = create_parser()
    args = parser.parse_args()

    if not args.command:
        # Default to status
        args.command = 'status'
        args.json = False
        return cmd_status(args)

    return args.func(args)


# =============================================================================
# SHELL WRAPPER CLASS
# =============================================================================

class ValidationShell:
    """Validation Shell wrapper for CLI integration."""

    def __init__(self):
        pass

    def status(self, as_json: bool = False) -> Dict[str, Any]:
        """Get shell status."""
        result = {
            'system': 'Validation Shell',
            'hex_id': 'F6F40F40',
            'version': '1.0.0',
            'validations': ['srl', 'morton', 'basin', 'ilogic', 'benchmark'],
            'status': 'operational',
        }
        if as_json:
            return json.dumps(result, indent=2)
        return result

    def validate_all(self, as_json: bool = False) -> Dict[str, Any]:
        """Run all validations."""
        results = ValidationResults()
        validate_srl(results)
        validate_morton(results)
        validate_basin(results)
        validate_ilogic(results)
        result = results.to_dict()
        if as_json:
            return json.dumps(result, indent=2)
        return result

    def run(self, command: str, *args, as_json: bool = False) -> Any:
        """Run a Validation shell command."""
        commands = {
            'status': lambda: self.status(as_json),
            'all': lambda: self.validate_all(as_json),
            'srl': lambda: self._run_srl(as_json),
            'morton': lambda: self._run_morton(as_json),
            'basin': lambda: self._run_basin(as_json),
            'ilogic': lambda: self._run_ilogic(as_json),
        }
        if command in commands:
            return commands[command]()
        return {'error': f'Unknown command: {command}', 'available': list(commands.keys())}

    def _run_srl(self, as_json: bool = False) -> Dict[str, Any]:
        results = ValidationResults()
        validate_srl(results)
        result = results.to_dict()
        if as_json:
            return json.dumps(result, indent=2)
        return result

    def _run_morton(self, as_json: bool = False) -> Dict[str, Any]:
        results = ValidationResults()
        validate_morton(results)
        result = results.to_dict()
        if as_json:
            return json.dumps(result, indent=2)
        return result

    def _run_basin(self, as_json: bool = False) -> Dict[str, Any]:
        results = ValidationResults()
        validate_basin(results)
        result = results.to_dict()
        if as_json:
            return json.dumps(result, indent=2)
        return result

    def _run_ilogic(self, as_json: bool = False) -> Dict[str, Any]:
        results = ValidationResults()
        validate_ilogic(results)
        result = results.to_dict()
        if as_json:
            return json.dumps(result, indent=2)
        return result


if __name__ == "__main__":
    sys.exit(main())
