"""ARIS Paradigm Detector — Identify available computing paradigms.

Scans hardware to determine which computing paradigms are available
on the current machine/cluster, enabling multi-paradigm routing.

Supported detection:
- Binary (always available)
- GPU/CUDA (NVIDIA via NVML)
- Neuromorphic (BrainChip Akida, Intel Loihi via USB/PCIe)
- Quantum (IBM Qiskit, IonQ, cloud APIs)
- Ternary (Huawei Ascend, FPGA-based)
- Photonic (Lightmatter, via PCIe)
- Ollama/Local AI (local LLM inference)
"""

import asyncio
import os
import shutil
from pathlib import Path
from typing import Any


async def _cmd(cmd: str) -> str:
    """Run a command and return stdout."""
    try:
        proc = await asyncio.create_subprocess_shell(
            cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
        )
        stdout, _ = await proc.communicate()
        return stdout.decode().strip()
    except Exception:
        return ""


async def detect_paradigms() -> dict[str, Any]:
    """Detect all available computing paradigms on this machine."""
    paradigms = {}

    # 1. BINARY (always available)
    paradigms["binary"] = {
        "available": True,
        "type": "native",
        "description": "Standard binary computing (CPU)",
    }

    # 2. GPU/CUDA
    try:
        import pynvml
        pynvml.nvmlInit()
        count = pynvml.nvmlDeviceGetCount()
        gpus = []
        for i in range(count):
            h = pynvml.nvmlDeviceGetHandleByIndex(i)
            name = pynvml.nvmlDeviceGetName(h)
            if isinstance(name, bytes):
                name = name.decode()
            mem = pynvml.nvmlDeviceGetMemoryInfo(h)
            gpus.append({"name": name, "vram_mb": mem.total // (1024*1024)})
        pynvml.nvmlShutdown()
        paradigms["gpu_cuda"] = {
            "available": True,
            "type": "native",
            "count": count,
            "devices": gpus,
            "description": "NVIDIA CUDA GPU parallel computing",
        }
    except Exception:
        paradigms["gpu_cuda"] = {"available": False, "type": "native"}

    # 3. NEUROMORPHIC (detect via USB/PCIe devices)
    akida = await _cmd("lsusb 2>/dev/null | grep -i 'brainchip\\|akida' || echo ''")
    loihi = await _cmd("lspci 2>/dev/null | grep -i 'loihi\\|neuromorphic\\|intel.*neural' || echo ''")
    paradigms["neuromorphic"] = {
        "available": bool(akida or loihi),
        "type": "native" if (akida or loihi) else "cloud",
        "akida_detected": bool(akida),
        "loihi_detected": bool(loihi),
        "cloud_options": ["Intel INRC (research)", "BrainChip MetaTF"],
        "description": "Brain-inspired spiking neural networks (1000x efficiency)",
    }

    # 4. QUANTUM (detect cloud SDKs)
    qiskit = shutil.which("qiskit") or await _cmd("python3 -c 'import qiskit; print(\"yes\")' 2>/dev/null")
    cirq = await _cmd("python3 -c 'import cirq; print(\"yes\")' 2>/dev/null")
    paradigms["quantum"] = {
        "available": bool(qiskit or cirq),
        "type": "cloud",
        "qiskit": bool(qiskit),
        "cirq": bool(cirq),
        "cloud_options": ["IBM Quantum (free tier)", "IonQ (via AWS Braket)", "Google Cirq"],
        "description": "Quantum computing for optimization and simulation",
    }

    # 5. TERNARY (detect Huawei Ascend NPU or FPGA)
    ascend = await _cmd("lspci 2>/dev/null | grep -i 'huawei\\|ascend\\|hisilicon' || echo ''")
    fpga = await _cmd("lspci 2>/dev/null | grep -i 'xilinx\\|altera\\|fpga\\|lattice' || echo ''")
    paradigms["ternary"] = {
        "available": bool(ascend or fpga),
        "type": "native" if ascend else "fpga" if fpga else "none",
        "ascend_detected": bool(ascend),
        "fpga_detected": bool(fpga),
        "description": "Three-state logic (-1,0,+1) — 60% more compute, 50% less energy",
    }

    # 6. OLLAMA / LOCAL AI
    ollama = await _cmd("curl -s http://localhost:11434/api/tags 2>/dev/null | head -1")
    models = []
    if ollama and "models" in ollama:
        import json
        try:
            data = json.loads(ollama)
            models = [m.get("name", "") for m in data.get("models", [])]
        except Exception:
            pass
    paradigms["local_ai"] = {
        "available": bool(ollama),
        "type": "native",
        "ollama_running": bool(ollama),
        "models": models[:10],
        "description": "Local AI inference (Ollama) — privacy-first, zero cost",
    }

    # 7. PHOTONIC (detect via PCIe - Lightmatter Passage)
    photonic = await _cmd("lspci 2>/dev/null | grep -i 'lightmatter\\|photonic\\|optical.*compute' || echo ''")
    paradigms["photonic"] = {
        "available": bool(photonic),
        "type": "native" if photonic else "none",
        "description": "Light-based computing — speed of light, zero heat",
    }

    # 8. MEMRISTIVE (detect crossbar arrays)
    paradigms["memristive"] = {
        "available": False,
        "type": "future",
        "description": "In-memory computing — eliminates von Neumann bottleneck",
    }

    # Summary
    available = [k for k, v in paradigms.items() if v.get("available")]
    cloud_available = [k for k, v in paradigms.items()
                       if v.get("type") == "cloud" and v.get("available")]

    return {
        "paradigms": paradigms,
        "available_native": [k for k, v in paradigms.items()
                             if v.get("available") and v.get("type") == "native"],
        "available_cloud": cloud_available,
        "total_available": len(available),
        "total_paradigms": len(paradigms),
    }


async def recommend_paradigm(task_type: str, paradigms: dict[str, Any]) -> dict[str, str]:
    """Given a task type, recommend the optimal computing paradigm."""
    avail = paradigms.get("paradigms", {})

    recommendations = {
        "inference": "neuromorphic" if avail.get("neuromorphic", {}).get("available")
                     else "gpu_cuda" if avail.get("gpu_cuda", {}).get("available")
                     else "local_ai" if avail.get("local_ai", {}).get("available")
                     else "binary",
        "training": "gpu_cuda" if avail.get("gpu_cuda", {}).get("available")
                    else "binary",
        "optimization": "quantum" if avail.get("quantum", {}).get("available")
                        else "gpu_cuda" if avail.get("gpu_cuda", {}).get("available")
                        else "binary",
        "bulk_text": "ternary" if avail.get("ternary", {}).get("available")
                     else "local_ai" if avail.get("local_ai", {}).get("available")
                     else "binary",
        "privacy": "local_ai" if avail.get("local_ai", {}).get("available")
                   else "binary",
        "interconnect": "photonic" if avail.get("photonic", {}).get("available")
                        else "binary",
        "storage": "binary",  # DNA storage not practical yet
        "security": "binary",  # Deterministic needed
    }

    paradigm = recommendations.get(task_type, "binary")
    return {
        "task_type": task_type,
        "recommended_paradigm": paradigm,
        "available": avail.get(paradigm, {}).get("available", False),
        "reason": avail.get(paradigm, {}).get("description", "Default"),
    }
