import json
import os
import shutil
import subprocess
import sys

import pytest

PLUGIN_DIR = os.path.join(os.path.dirname(__file__), "..", ".kilo", "plugin", "cyberbrain26-freeauto")

def test_plugin_manifest_exists():
    """Plugin manifest file exists and is valid JSON."""
    manifest_path = os.path.join(PLUGIN_DIR, "plugin.json")
    assert os.path.exists(manifest_path), f"Missing {manifest_path}"
    with open(manifest_path) as f:
        manifest = json.load(f)
    assert manifest["name"] == "cyberbrain26-freeauto"
    assert manifest["entry"] == "src/index.ts"

def test_config_valid():
    """Config file exists and has required role mappings."""
    config_path = os.path.join(PLUGIN_DIR, "cyberbrain26-freeauto.config.json")
    assert os.path.exists(config_path), f"Missing {config_path}"
    with open(config_path) as f:
        config = json.load(f)
    assert "roles" in config
    assert config["roles"]["orchestrator"] == "free"
    assert config["roles"]["coder"] == "efficient"

def test_cli_list_models():
    """Python CLI returns valid model list."""
    result = subprocess.run(
        [sys.executable, "-m", "cyberbrain26.model_layer.cli", "list-models"],
        capture_output=True, text=True, cwd="/home/oem/CyberBrain26-v4",
        timeout=30
    )
    assert result.returncode == 0, f"CLI failed: {result.stderr}"
    models = json.loads(result.stdout.strip())
    assert isinstance(models, list)
    assert len(models) >= 2
    model_ids = {m["model_id"] for m in models}
    assert "free" in model_ids
    assert "efficient" in model_ids

def test_bridge_typescript_compiles():
    """TypeScript compiles without errors."""
    npx = shutil.which("npx")
    if npx is None:
        pytest.skip("npx not available")
    try:
        result = subprocess.run(
            [npx, "tsc", "--noEmit"],
            capture_output=True, text=True, cwd=PLUGIN_DIR,
            timeout=30
        )
    except FileNotFoundError:
        pytest.skip("TypeScript compiler (npx) not available")
    # If npx/tsc not available, skip gracefully
    output = result.stdout + result.stderr
    if result.returncode != 0 and ("command not found" in output or "not the tsc command" in output):
        pytest.skip("TypeScript compiler not available")
    assert result.returncode == 0, f"TS compile failed: {result.stderr}"

def test_anonymizer_logic():
    """Test anonymization logic directly (Python port of TS logic)."""
    import re
    test_input = {
        "email": "admin@example.com",
        "ip": "192.168.1.1",
        "phone": "123-456-7890",
        "ssn": "123-45-6789",
        "api_key": "sk_live_abcdefghijklmnopqrstuvwxyz123456",
        "cc": "4532-1234-5678-9012",
        "marker": "CB26_MARKER_abc123def456"
    }
    str_input = json.dumps(test_input)
    cleaned = str_input
    # Order matters: more specific patterns first
    cleaned = re.sub(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', "[REDACTED_EMAIL]", cleaned)
    cleaned = re.sub(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b', "[REDACTED_IP]", cleaned)
    cleaned = re.sub(r'\b\d{3}-\d{2}-\d{4}\b', "[REDACTED_SSN]", cleaned)  # SSN before phone
    cleaned = re.sub(r'\b\d{3}[-.]?\d{3}[-.]?\d{4}\b', "[REDACTED_PHONE]", cleaned)
    cleaned = re.sub(r'[A-Za-z0-9_-]{32,}', "[REDACTED_API_KEY]", cleaned)
    cleaned = re.sub(r'\bCB26_MARKER_[A-Za-z0-9_-]+\b', "", cleaned)
    
    assert "[REDACTED_EMAIL]" in cleaned
    assert "[REDACTED_IP]" in cleaned
    assert "[REDACTED_PHONE]" in cleaned
    assert "[REDACTED_SSN]" in cleaned
    assert "[REDACTED_API_KEY]" in cleaned
    assert "CB26_MARKER_" not in cleaned

def test_kilo_snapshot_command_exists():
    """kilo snapshot command is available."""
    kilo = shutil.which("kilo")
    if kilo is None:
        pytest.skip("kilo CLI not available")
    try:
        result = subprocess.run(
            [kilo, "--help"],
            capture_output=True, text=True, cwd="/home/oem/CyberBrain26-v4",
            timeout=30
        )
    except subprocess.TimeoutExpired:
        pytest.skip("kilo CLI not available")
    assert result.returncode == 0 or "kilo" in result.stdout.lower()
