"""SDK Self-Audit — GraQle auditing itself using ALL engineering skills.

Uses the full engineering domain (45 skills across 8 categories) to find
gaps, security issues, performance problems, and architectural concerns
in the SDK codebase. Production-grade scaling assessment.

Run: PYTHONIOENCODING=utf-8 python sdk_self_audit.py
"""

# ── graqle:intelligence ──
# module: sdk_self_audit
# risk: MEDIUM (impact radius: 0 modules)
# dependencies: __future__, json, re, sys, collections +7 more
# constraints: none
# ── /graqle:intelligence ──

from __future__ import annotations

import json
import re
import sys
from collections import defaultdict
from pathlib import Path

# Ensure UTF-8 output
sys.stdout.reconfigure(encoding="utf-8", errors="replace")

from graqle.core.graph import Graqle
from graqle.config.settings import GraqleConfig
from graqle.ontology.skill_pipeline import SkillPipeline
from graqle.ontology.domain_registry import DomainRegistry
from graqle.ontology.domains import register_all_domains, collect_all_skills
from graqle.ontology.domains.engineering import ENGINEERING_SKILLS, ENGINEERING_SKILL_MAP


# ─── Utility helpers ──────────────────────────────────────────────────
def _node_text(node, max_chunks: int = 5, max_chars: int = 1000) -> str:
    """Extract combined description + chunk text from a node."""
    chunks = node.properties.get("chunks", [])
    chunk_text = " ".join(
        c.get("text", "")[:max_chars] if isinstance(c, dict) else str(c)[:max_chars]
        for c in chunks[:max_chunks]
    )
    desc = node.description or ""
    return f"{desc} {chunk_text}".lower()


def _has_test_neighbor(graph, node) -> bool:
    """Check if any neighbor is a test file."""
    for nid in graph.get_neighbors(node.id):
        if nid in graph.nodes:
            n = graph.nodes[nid]
            if "test" in nid.lower() or n.entity_type in ("TestFile", "TEST_SUITE", "TEST_CASE"):
                return True
    return False


# ─── Skill-based auditors (one per engineering skill category) ────────

def audit_code_quality(graph, pipeline) -> dict:
    """Skills: code_review, complexity_analysis, dead_code_detection,
    naming_convention_check, class_design_review, inheritance_analysis,
    input_validation_check, error_handling_review"""
    issues = []
    code_types = {"Function", "Class", "PythonModule", "PythonClass", "PythonFunction",
                  "MODULE", "CLASS", "FUNCTION", "JavaScriptModule"}

    god_classes = []        # class_design_review
    complex_modules = []    # complexity_analysis
    naming_issues = []      # naming_convention_check
    dead_code = []          # dead_code_detection
    error_handling = []     # error_handling_review
    input_validation = []   # input_validation_check

    for nid, node in graph.nodes.items():
        if node.entity_type not in code_types:
            continue
        text = _node_text(node)
        degree = node.degree

        # complexity_analysis: high-degree modules indicate high complexity
        if degree >= 20:
            complex_modules.append({
                "node": nid, "type": node.entity_type, "degree": degree,
                "skill": "complexity_analysis",
                "issue": f"Very high complexity — {degree} connections, likely needs decomposition",
            })
        elif degree >= 10:
            complex_modules.append({
                "node": nid, "type": node.entity_type, "degree": degree,
                "skill": "complexity_analysis",
                "issue": f"Moderate complexity — {degree} connections, review for single responsibility",
            })

        # class_design_review: god classes (high-degree Class nodes)
        if node.entity_type in ("Class", "PythonClass", "CLASS") and degree >= 15:
            god_classes.append({
                "node": nid, "degree": degree,
                "skill": "class_design_review",
                "issue": f"Potential god class — {degree} connections, may violate SRP",
            })

        # naming_convention_check
        base = nid.split("/")[-1].split(".")[-1] if "/" in nid else nid
        if base and not base.startswith("_"):
            # Check for inconsistent naming (CamelCase in Python module names)
            if node.entity_type in ("PythonModule",) and any(c.isupper() for c in base[1:]) and "_" not in base:
                pass  # CamelCase module names are common in Python — not an issue by default
            # Check for very short names
            if len(base) <= 2 and node.entity_type in ("Function", "PythonFunction", "FUNCTION"):
                naming_issues.append({
                    "node": nid, "skill": "naming_convention_check",
                    "issue": f"Very short name '{base}' — may hurt readability",
                })

        # dead_code_detection: zero-degree nodes that aren't test files
        if degree == 0 and node.entity_type not in ("TestFile", "TEST_SUITE", "TEST_CASE", "Directory", "Dependency"):
            dead_code.append({
                "node": nid, "type": node.entity_type,
                "skill": "dead_code_detection",
                "issue": "Zero connections — potentially unused/dead code",
            })

        # error_handling_review
        if "except" in text:
            if "except:" in text or "except exception" in text:
                if "pass" in text or "continue" in text:
                    error_handling.append({
                        "node": nid, "type": node.entity_type,
                        "skill": "error_handling_review",
                        "issue": "Broad exception handler with pass/continue — may hide errors",
                        "severity": "MEDIUM",
                    })
            if "bare except" in text or (re.search(r"except\s*:", text)):
                error_handling.append({
                    "node": nid, "type": node.entity_type,
                    "skill": "error_handling_review",
                    "issue": "Bare except clause — catch specific exceptions instead",
                    "severity": "LOW",
                })

        # input_validation_check
        if node.entity_type in ("Function", "PythonFunction", "FUNCTION", "HANDLER"):
            if any(k in text for k in ["user_input", "request.body", "request.json", "form_data", "file_upload"]):
                if "validate" not in text and "sanitize" not in text and "schema" not in text:
                    input_validation.append({
                        "node": nid, "skill": "input_validation_check",
                        "issue": "Handles user input without visible validation/sanitization",
                    })

    return {
        "god_classes": god_classes,
        "complex_modules": complex_modules[:20],
        "naming_issues": naming_issues[:10],
        "dead_code": dead_code[:20],
        "error_handling": error_handling,
        "input_validation": input_validation,
    }


def audit_architecture(graph, pipeline) -> dict:
    """Skills: analyze_dependencies, trace_data_flow, check_error_handling,
    middleware_chain_analysis, accessibility_check, analyze_react_component"""
    circular_deps = []      # analyze_dependencies
    high_coupling = []      # analyze_dependencies
    orphan_modules = []     # trace_data_flow

    # analyze_dependencies: find high fan-out nodes (coupling)
    # Use degree as proxy — high-degree modules have many connections
    for nid, node in graph.nodes.items():
        if node.entity_type in ("PythonModule", "MODULE", "JavaScriptModule"):
            neighbors = graph.get_neighbors(nid)
            fan_out = len(neighbors)
            if fan_out > 15:
                high_coupling.append({
                    "node": nid, "fan_out": fan_out,
                    "skill": "analyze_dependencies",
                    "issue": f"High fan-out ({fan_out} connections) — tight coupling risk",
                })

    # trace_data_flow: find orphan modules (zero-degree code nodes)
    for nid, node in graph.nodes.items():
        if node.entity_type in ("PythonModule", "MODULE"):
            if node.degree == 0:
                orphan_modules.append({
                    "node": nid, "degree": node.degree,
                    "skill": "trace_data_flow",
                    "issue": "Isolated module with zero connections — dead code or missing links",
                })

    return {
        "circular_deps": circular_deps,
        "high_coupling": high_coupling[:15],
        "orphan_modules": orphan_modules[:15],
    }


def audit_api_integration(graph, pipeline) -> dict:
    """Skills: analyze_api_endpoint, api_contract_check, rate_limit_review,
    trace_state_flow, analyze_css_styles"""
    api_issues = []
    no_auth = []
    no_rate_limit = []
    no_schema = []

    for nid, node in graph.nodes.items():
        if node.entity_type != "APIEndpoint":
            continue
        text = _node_text(node)

        # analyze_api_endpoint + audit_auth_flow
        if "auth" not in text and "token" not in text and "jwt" not in text and "api_key" not in text:
            no_auth.append({
                "node": nid, "skill": "audit_auth_flow",
                "description": (node.description or "")[:100],
                "issue": "API endpoint without visible auth mechanism",
            })

        # rate_limit_review
        if "rate_limit" not in text and "throttl" not in text:
            no_rate_limit.append({
                "node": nid, "skill": "rate_limit_review",
                "issue": "No rate limiting mentioned — DoS risk for production",
            })

        # api_contract_check
        if "schema" not in text and "openapi" not in text and "pydantic" not in text:
            no_schema.append({
                "node": nid, "skill": "api_contract_check",
                "issue": "No schema validation mentioned — contract drift risk",
            })

    return {
        "no_auth": no_auth,
        "no_rate_limit": no_rate_limit[:15],
        "no_schema": no_schema[:15],
    }


def audit_data_database(graph, pipeline) -> dict:
    """Skills: analyze_schema, query_optimization, index_analysis,
    migration_safety_check, check_data_integrity"""
    issues = []
    db_types = {"DatabaseModel", "DATABASE", "SCHEMA", "MIGRATION", "QUERY"}

    for nid, node in graph.nodes.items():
        if node.entity_type not in db_types:
            continue
        text = _node_text(node)

        # query_optimization
        if any(k in text for k in ["select *", "fetch_all", "no_index", "full_scan"]):
            issues.append({
                "node": nid, "skill": "query_optimization",
                "issue": "Potential full table scan or unoptimized query pattern",
            })

        # check_data_integrity
        if "nullable" in text and "required" not in text:
            issues.append({
                "node": nid, "skill": "check_data_integrity",
                "issue": "Nullable field without clear required/optional documentation",
            })

    return {"data_issues": issues}


def audit_infrastructure(graph, pipeline) -> dict:
    """Skills: analyze_deployment, check_env_config, lambda_config_review,
    cold_start_analysis, container_config_review, resource_limit_check"""
    env_issues = []
    lambda_issues = []
    container_issues = []

    for nid, node in graph.nodes.items():
        text = _node_text(node)

        # check_env_config
        if node.entity_type in ("EnvVar", "ENV_VAR"):
            if "required" not in text and "must" not in text and "optional" not in text:
                env_issues.append({
                    "node": nid, "skill": "check_env_config",
                    "issue": "Environment variable without required/optional documentation",
                })
            if "default" not in text:
                env_issues.append({
                    "node": nid, "skill": "check_env_config",
                    "issue": "No default value — will crash if not set",
                })

        # lambda_config_review
        if node.entity_type in ("LAMBDA",):
            if "timeout" not in text:
                lambda_issues.append({
                    "node": nid, "skill": "lambda_config_review",
                    "issue": "Lambda without explicit timeout — will use default 3s",
                })
            if "memory" not in text:
                lambda_issues.append({
                    "node": nid, "skill": "lambda_config_review",
                    "issue": "Lambda without explicit memory config — may OOM on large graphs",
                })

        # container_config_review
        if node.entity_type in ("DockerService", "CONTAINER"):
            if "healthcheck" not in text and "health_check" not in text:
                container_issues.append({
                    "node": nid, "skill": "container_config_review",
                    "issue": "Container without health check — orchestrator can't detect failures",
                })

    return {
        "env_issues": env_issues[:20],
        "lambda_issues": lambda_issues,
        "container_issues": container_issues,
    }


def audit_security(graph, pipeline) -> dict:
    """Skills: audit_auth_flow, check_injection_risk, flag_secrets,
    secret_rotation_check, check_dependency_risk, cache_policy_review"""
    secrets = []
    injection_risks = []
    dependency_risks = []

    for nid, node in graph.nodes.items():
        text = _node_text(node)

        # flag_secrets
        if any(k in text for k in ["password", "secret", "api_key", "private_key", "credential"]):
            if "hardcod" in text or "plain" in text:
                secrets.append({
                    "node": nid, "type": node.entity_type, "severity": "HIGH",
                    "skill": "flag_secrets",
                    "issue": "Potential hardcoded credential or plaintext secret",
                })
            elif "env" not in text and "environ" not in text and "vault" not in text and "ssm" not in text:
                secrets.append({
                    "node": nid, "type": node.entity_type, "severity": "MEDIUM",
                    "skill": "flag_secrets",
                    "issue": "Secret handling without clear env/vault/SSM reference",
                })

        # check_injection_risk — look for actual dangerous patterns in code chunks
        # Only check chunk text (code), not descriptions (which may just name the module)
        chunks = node.properties.get("chunks", [])
        code_text = " ".join(
            c.get("text", "")[:1000].lower() if isinstance(c, dict) else str(c)[:1000].lower()
            for c in chunks[:5]
        )
        has_interpolation = any(k in code_text for k in [".format(", "%s"])
        has_dangerous_target = any(k in code_text for k in ["sql", "cypher", "gremlin", "shell_exec", "os.system", "subprocess.run", "subprocess.call", "eval(", "exec("])
        if has_interpolation and has_dangerous_target:
            injection_risks.append({
                "node": nid, "type": node.entity_type,
                "skill": "check_injection_risk",
                "issue": "String interpolation near query/command execution — injection risk",
                "severity": "HIGH",
            })

        # check_dependency_risk
        if node.entity_type == "Dependency":
            if "deprecated" in text or "unmaintained" in text or "archived" in text:
                dependency_risks.append({
                    "node": nid, "skill": "check_dependency_risk",
                    "issue": "Dependency may be deprecated/unmaintained",
                })

    return {
        "secrets": secrets,
        "injection_risks": injection_risks,
        "dependency_risks": dependency_risks,
    }


def audit_testing(graph, pipeline) -> dict:
    """Skills: identify_test_gaps, suggest_edge_cases, analyze_test_quality,
    test_coverage_analysis, rollback_plan_check"""
    untested_modules = []
    test_quality = []
    coverage_gaps = []

    code_types = {"Function", "Class", "PythonModule", "PythonClass", "PythonFunction",
                  "MODULE", "CLASS", "FUNCTION"}

    # identify_test_gaps + test_coverage_analysis
    for nid, node in graph.nodes.items():
        if node.entity_type not in code_types:
            continue
        if not _has_test_neighbor(graph, node):
            if node.degree >= 3:
                untested_modules.append({
                    "node": nid, "type": node.entity_type, "degree": node.degree,
                    "skill": "identify_test_gaps",
                    "issue": f"Module with {node.degree} connections has no linked test",
                    "priority": "HIGH" if node.degree >= 8 else "MEDIUM",
                })

    # analyze_test_quality
    for nid, node in graph.nodes.items():
        if node.entity_type not in ("TestFile", "TEST_SUITE", "TEST_CASE"):
            continue
        text = _node_text(node)

        if "assert" not in text:
            test_quality.append({
                "node": nid, "skill": "analyze_test_quality",
                "issue": "Test file without visible assertions — may be a no-op",
            })
        if "mock" in text and "patch" in text:
            # Heavy mocking = brittle tests
            mock_count = text.count("mock") + text.count("patch")
            if mock_count > 5:
                test_quality.append({
                    "node": nid, "skill": "analyze_test_quality",
                    "issue": f"Heavy mocking ({mock_count} references) — brittle, may diverge from prod",
                })

    return {
        "untested_modules": sorted(untested_modules, key=lambda x: -x["degree"])[:25],
        "test_quality": test_quality[:15],
        "coverage_gaps": coverage_gaps,
    }


def audit_performance(graph, pipeline) -> dict:
    """Skills: performance_profiling, pipeline_efficiency, deploy_safety_check,
    service_health_check"""
    timeout_configs = []
    performance_issues = []
    scaling_issues = []

    for nid, node in graph.nodes.items():
        text = _node_text(node)

        # Timeout audit (performance_profiling)
        if "timeout" in text and node.entity_type in ("PythonModule", "Function", "Class", "Config",
                                                       "MODULE", "FUNCTION", "CLASS", "CONFIG"):
            timeout_configs.append({
                "node": nid, "type": node.entity_type,
                "skill": "performance_profiling",
                "description": (node.description or "")[:150],
            })

        # Scaling issues
        if any(k in text for k in ["for node in", "for nid in", "for n in"]):
            if any(k in text for k in ["graph.nodes", "all_nodes", "self.nodes"]):
                if "async" not in text and "batch" not in text:
                    scaling_issues.append({
                        "node": nid, "type": node.entity_type,
                        "skill": "performance_profiling",
                        "issue": "Synchronous iteration over all nodes — O(n) scaling risk for large graphs",
                    })

        # Memory issues
        if any(k in text for k in ["load_all", "read_all", "fetch_all", "list(graph"]):
            performance_issues.append({
                "node": nid, "type": node.entity_type,
                "skill": "performance_profiling",
                "issue": "Loading entire dataset into memory — OOM risk on large graphs",
            })

    # Adaptive timeout assessment
    from graqle.orchestration.async_protocol import AsyncMessageProtocol
    node_count = len(graph.nodes)
    adaptive_wave = AsyncMessageProtocol.adaptive_wave_timeout(node_count)

    from graqle.backends.api import BedrockBackend
    adaptive_read = BedrockBackend.adaptive_read_timeout(activated_nodes=50)

    return {
        "timeout_configs": timeout_configs[:20],
        "performance_issues": performance_issues[:15],
        "scaling_issues": scaling_issues[:15],
        "adaptive_timeouts": {
            "graph_nodes": node_count,
            "adaptive_wave_timeout_s": adaptive_wave,
            "adaptive_read_timeout_s": adaptive_read,
            "status": "IMPLEMENTED",
        },
    }


# ─── Main ─────────────────────────────────────────────────────────────

def main():
    print("=" * 70)
    print("GRAQLE SDK SELF-AUDIT — v0.23.1 (Full Engineering Domain)")
    print("All 45 engineering skills × 3,749 nodes = production-grade assessment")
    print("=" * 70)

    cfg = GraqleConfig.from_yaml("graqle.yaml")
    graph = Graqle.from_json("graqle.json", config=cfg)
    print(f"\nGraph: {len(graph.nodes)} nodes, {len(graph.edges)} edges")

    # Set up skill pipeline
    registry = DomainRegistry()
    register_all_domains(registry, only=["engineering"])
    pipeline = SkillPipeline(mode="type_only", registry=registry)
    pipeline.register_domain_skills(ENGINEERING_SKILLS)
    print(f"Pipeline: {pipeline.stats}")

    # Skill resolution coverage
    print(f"\n{'=' * 70}")
    print("SKILL RESOLUTION COVERAGE")
    print(f"{'=' * 70}")

    type_counts = defaultdict(int)
    type_skill_counts = defaultdict(int)
    for node in graph.nodes.values():
        type_counts[node.entity_type] += 1
        skills = pipeline._resolve_by_type(node.entity_type)
        domain_skills = [s for s in skills if s.name not in {"cite_evidence", "state_confidence", "flag_contradiction"}]
        type_skill_counts[node.entity_type] = len(domain_skills)

    total_covered = sum(c for t, c in type_counts.items() if type_skill_counts.get(t, 0) > 0)
    total_nodes = len(graph.nodes)
    coverage_pct = (total_covered / total_nodes * 100) if total_nodes > 0 else 0

    print(f"\n  Skill coverage: {total_covered}/{total_nodes} nodes ({coverage_pct:.1f}%)")
    for t, c in sorted(type_counts.items(), key=lambda x: -x[1])[:15]:
        sc = type_skill_counts.get(t, 0)
        marker = "OK" if sc > 0 else "NO SKILLS"
        print(f"  {t:25s} {c:5d} nodes  ->  {sc} domain skills [{marker}]")

    # Run all 8 audit categories
    print(f"\n{'=' * 70}")
    print("RUNNING ALL ENGINEERING SKILL AUDITS")
    print(f"{'=' * 70}")

    results = {}

    # 1. Code Quality (8 skills)
    print("\n  [1/8] Code Quality (code_review, complexity_analysis, dead_code, naming, class_design, inheritance, input_validation, error_handling)...")
    results["code_quality"] = audit_code_quality(graph, pipeline)

    # 2. Architecture (6 skills)
    print("  [2/8] Architecture (analyze_dependencies, trace_data_flow, check_error_handling, middleware_chain, accessibility, react_component)...")
    results["architecture"] = audit_architecture(graph, pipeline)

    # 3. API & Integration (5 skills)
    print("  [3/8] API & Integration (analyze_api_endpoint, api_contract_check, rate_limit_review, trace_state_flow, css_styles)...")
    results["api_integration"] = audit_api_integration(graph, pipeline)

    # 4. Data & Database (5 skills)
    print("  [4/8] Data & Database (analyze_schema, query_optimization, index_analysis, migration_safety, data_integrity)...")
    results["data_database"] = audit_data_database(graph, pipeline)

    # 5. Infrastructure (6 skills)
    print("  [5/8] Infrastructure (analyze_deployment, check_env_config, lambda_config, cold_start, container_config, resource_limits)...")
    results["infrastructure"] = audit_infrastructure(graph, pipeline)

    # 6. Security (6 skills)
    print("  [6/8] Security (audit_auth_flow, check_injection_risk, flag_secrets, secret_rotation, dependency_risk, cache_policy)...")
    results["security"] = audit_security(graph, pipeline)

    # 7. Testing (5 skills)
    print("  [7/8] Testing (identify_test_gaps, suggest_edge_cases, analyze_test_quality, test_coverage, rollback_plan)...")
    results["testing"] = audit_testing(graph, pipeline)

    # 8. Performance (4 skills)
    print("  [8/8] Performance (performance_profiling, pipeline_efficiency, deploy_safety, service_health)...")
    results["performance"] = audit_performance(graph, pipeline)

    # ── Report ────────────────────────────────────────────────────────
    print(f"\n{'=' * 70}")
    print("AUDIT RESULTS BY CATEGORY")
    print(f"{'=' * 70}")

    # Code Quality
    cq = results["code_quality"]
    print(f"\n## 1. CODE QUALITY")
    print(f"  God classes:        {len(cq['god_classes'])}")
    for i in cq["god_classes"][:5]:
        print(f"    {i['node']} (degree={i['degree']}): {i['issue']}")
    print(f"  Complex modules:    {len(cq['complex_modules'])}")
    for i in cq["complex_modules"][:5]:
        print(f"    {i['node']} (degree={i['degree']}): {i['issue']}")
    print(f"  Dead code:          {len(cq['dead_code'])}")
    for i in cq["dead_code"][:5]:
        print(f"    [{i['type']}] {i['node']}")
    print(f"  Error handling:     {len(cq['error_handling'])}")
    for i in cq["error_handling"][:5]:
        print(f"    [{i.get('severity','?')}] {i['node']}: {i['issue']}")
    print(f"  Input validation:   {len(cq['input_validation'])}")
    print(f"  Naming issues:      {len(cq['naming_issues'])}")

    # Architecture
    arch = results["architecture"]
    print(f"\n## 2. ARCHITECTURE")
    print(f"  High coupling:      {len(arch['high_coupling'])}")
    for i in arch["high_coupling"][:5]:
        print(f"    {i['node']} fan_out={i['fan_out']}: {i['issue']}")
    print(f"  Orphan modules:     {len(arch['orphan_modules'])}")

    # API
    api = results["api_integration"]
    print(f"\n## 3. API & INTEGRATION")
    print(f"  No auth:            {len(api['no_auth'])}")
    print(f"  No rate limit:      {len(api['no_rate_limit'])}")
    print(f"  No schema:          {len(api['no_schema'])}")

    # Data
    db = results["data_database"]
    print(f"\n## 4. DATA & DATABASE")
    print(f"  Data issues:        {len(db['data_issues'])}")

    # Infrastructure
    infra = results["infrastructure"]
    print(f"\n## 5. INFRASTRUCTURE")
    print(f"  Env var issues:     {len(infra['env_issues'])}")
    for i in infra["env_issues"][:5]:
        print(f"    {i['node']}: {i['issue']}")
    print(f"  Lambda issues:      {len(infra['lambda_issues'])}")
    print(f"  Container issues:   {len(infra['container_issues'])}")

    # Security
    sec = results["security"]
    print(f"\n## 6. SECURITY")
    print(f"  Secrets:            {len(sec['secrets'])}")
    for i in sec["secrets"][:5]:
        print(f"    [{i['severity']}] {i['node']}: {i['issue']}")
    print(f"  Injection risks:    {len(sec['injection_risks'])}")
    for i in sec["injection_risks"][:5]:
        print(f"    [{i['severity']}] {i['node']}: {i['issue']}")
    print(f"  Dependency risks:   {len(sec['dependency_risks'])}")

    # Testing
    test = results["testing"]
    print(f"\n## 7. TESTING")
    print(f"  Untested modules:   {len(test['untested_modules'])}")
    for i in test["untested_modules"][:10]:
        print(f"    [{i['priority']}] {i['node']} (degree={i['degree']})")
    print(f"  Test quality:       {len(test['test_quality'])}")
    for i in test["test_quality"][:5]:
        print(f"    {i['node']}: {i['issue']}")

    # Performance
    perf = results["performance"]
    print(f"\n## 8. PERFORMANCE")
    print(f"  Timeout configs:    {len(perf['timeout_configs'])}")
    print(f"  Scaling issues:     {len(perf['scaling_issues'])}")
    for i in perf["scaling_issues"][:5]:
        print(f"    {i['node']}: {i['issue']}")
    print(f"  Memory issues:      {len(perf['performance_issues'])}")
    at = perf["adaptive_timeouts"]
    print(f"  Adaptive timeouts:  [{at['status']}]")
    print(f"    Graph: {at['graph_nodes']} nodes")
    print(f"    wave_timeout: {at['adaptive_wave_timeout_s']:.0f}s (adaptive)")
    print(f"    read_timeout: {at['adaptive_read_timeout_s']:.0f}s (adaptive, 50 activated nodes)")

    # ── Summary ───────────────────────────────────────────────────────
    total_issues = sum(
        len(v) for cat in results.values()
        for k, v in cat.items() if isinstance(v, list)
    )

    print(f"\n{'=' * 70}")
    print(f"SUMMARY — PRODUCTION READINESS ASSESSMENT")
    print(f"{'=' * 70}")
    print(f"  Total nodes scanned:     {len(graph.nodes)}")
    print(f"  Skill coverage:          {coverage_pct:.1f}%")
    print(f"  Engineering skills used: {len(ENGINEERING_SKILLS)}")
    print(f"  Total issues found:      {total_issues}")
    print(f"")
    print(f"  CATEGORY BREAKDOWN:")
    for cat_name, cat_results in results.items():
        cat_count = sum(len(v) for k, v in cat_results.items() if isinstance(v, list))
        print(f"    {cat_name:25s} {cat_count:5d} issues")

    # Production readiness score
    # Only count actual HIGH-severity secrets (hardcoded), not MEDIUM (just mentioned)
    high_secrets = [i for i in sec.get("secrets", []) if i.get("severity") == "HIGH"]
    high_severity = (
        len(high_secrets) +
        len(sec.get("injection_risks", [])) +
        len([i for i in cq.get("error_handling", []) if i.get("severity") == "HIGH"])
    )
    med_severity = (
        len(cq.get("god_classes", [])) +
        len([i for i in test.get("untested_modules", []) if i.get("priority") == "HIGH"]) +
        min(len(infra.get("env_issues", [])), 10)  # Cap env issues impact
    )

    score = max(0, 100 - high_severity * 5 - med_severity * 2 - len(perf.get("scaling_issues", [])) * 1)
    grade = "A" if score >= 90 else "B" if score >= 75 else "C" if score >= 60 else "D" if score >= 40 else "F"

    print(f"\n  PRODUCTION READINESS: {score}/100 (Grade: {grade})")
    print(f"    High severity: {high_severity} (×5 penalty)")
    print(f"    Medium severity: {med_severity} (×2 penalty)")
    print(f"    Scaling risks: {len(perf.get('scaling_issues', []))} (×1 penalty)")

    if high_severity > 0:
        print(f"\n  [ACTION REQUIRED] Fix {high_severity} high-severity issues before production deployment")
    if coverage_pct < 80:
        print(f"  [ACTION REQUIRED] Skill coverage {coverage_pct:.0f}% below 80% threshold")

    # ── Save report ───────────────────────────────────────────────────
    report = {
        "sdk_version": "0.23.1",
        "graph_nodes": len(graph.nodes),
        "graph_edges": len(graph.edges),
        "skill_coverage_pct": round(coverage_pct, 1),
        "skills_used": len(ENGINEERING_SKILLS),
        "total_issues": total_issues,
        "production_readiness_score": score,
        "production_readiness_grade": grade,
        **results,
    }
    Path("sdk_audit_report.json").write_text(
        json.dumps(report, indent=2, default=str), encoding="utf-8"
    )
    print(f"\n  Full report saved to: sdk_audit_report.json")


if __name__ == "__main__":
    main()
