"""Framework auto-detection for agentic AI projects.

Scans a project directory to identify which agentic AI framework(s)
are in use, based on imports, dependencies, and configuration files.
"""

from pathlib import Path

FRAMEWORK_SIGNATURES: dict[str, dict] = {
    "LangChain": {
        "imports": ["langchain", "langchain_core", "langchain_community", "langchain_openai"],
        "packages": ["langchain", "langchain-core", "langchain-community"],
        "config_files": [],
    },
    "LangGraph": {
        "imports": ["langgraph"],
        "packages": ["langgraph"],
        "config_files": ["langgraph.json"],
    },
    "CrewAI": {
        "imports": ["crewai"],
        "packages": ["crewai"],
        "config_files": [],
    },
    "AutoGen": {
        "imports": ["autogen", "autogen_agentchat", "autogen_core", "autogen_ext"],
        "packages": ["autogen", "pyautogen", "autogen-agentchat"],
        "config_files": ["OAI_CONFIG_LIST"],
    },
    "OpenAI Assistants": {
        "imports": ["openai"],
        "packages": ["openai"],
        "config_files": [],
        "api_patterns": ["client.beta.assistants", "client.beta.threads"],
    },
    "Claude SDK": {
        "imports": ["anthropic", "claude_agent_sdk"],
        "packages": ["anthropic", "claude-agent-sdk"],
        "config_files": ["claude.json", "CLAUDE.md"],
    },
    "LlamaIndex": {
        "imports": ["llama_index", "llama_index.core"],
        "packages": ["llama-index", "llama-index-core"],
        "config_files": [],
    },
    "Semantic Kernel": {
        "imports": ["semantic_kernel"],
        "packages": ["semantic-kernel"],
        "config_files": [],
    },
    "Google ADK": {
        "imports": ["google.adk", "google_adk"],
        "packages": ["google-adk"],
        "config_files": [],
    },
}


def detect_frameworks(project_path: Path) -> dict[str, float]:
    """Detect which frameworks are used in a project.

    Returns a dict of framework_name -> confidence (0.0 to 1.0).
    """
    results: dict[str, float] = {}
    source_content = _collect_source_content(project_path)
    dep_content = _collect_dependency_content(project_path)

    for framework, sigs in FRAMEWORK_SIGNATURES.items():
        score = 0.0
        checks = 0

        # Check imports in source files
        for imp in sigs["imports"]:
            checks += 1
            if f"import {imp}" in source_content or f"from {imp}" in source_content:
                score += 1

        # Check packages in dependency files
        for pkg in sigs["packages"]:
            checks += 1
            if pkg in dep_content:
                score += 1

        # Check config files
        for cfg in sigs.get("config_files", []):
            checks += 1
            if (project_path / cfg).exists():
                score += 1

        # Check API-specific patterns
        for pattern in sigs.get("api_patterns", []):
            checks += 1
            if pattern in source_content:
                score += 1

        if checks > 0 and score > 0:
            results[framework] = min(score / max(checks * 0.4, 1), 1.0)

    return results


def _collect_source_content(project_path: Path) -> str:
    """Read all Python source files and concatenate their content."""
    content_parts: list[str] = []
    try:
        for py_file in project_path.rglob("*.py"):
            # Skip venvs and hidden dirs
            parts = py_file.parts
            if any(p.startswith(".") or p in ("venv", "env", ".venv", "node_modules", "__pycache__", ".git") for p in parts):
                continue
            try:
                text = py_file.read_text(errors="ignore")
                if len(text) < 500_000:  # Skip very large files
                    content_parts.append(text)
            except (PermissionError, OSError):
                continue
    except (PermissionError, OSError):
        pass
    return "\n".join(content_parts)


def _collect_dependency_content(project_path: Path) -> str:
    """Read dependency files (requirements.txt, pyproject.toml, etc.)."""
    dep_files = [
        "requirements.txt", "requirements-dev.txt", "requirements-test.txt",
        "pyproject.toml", "setup.py", "setup.cfg", "Pipfile", "poetry.lock",
        "conda.yaml", "environment.yml",
    ]
    content_parts: list[str] = []
    for dep_file in dep_files:
        path = project_path / dep_file
        if path.exists():
            try:
                content_parts.append(path.read_text(errors="ignore"))
            except (PermissionError, OSError):
                continue
    return "\n".join(content_parts)
