#!/usr/bin/env python3
"""Pre-commit hook to enforce that infrastructure packages do not import from web/.

Packages like settings/, utilities/, security/, and config/ should not depend
on web/ — this breaks CLI, MCP, and programmatic API usage.
"""

import re
import sys

# Infrastructure packages that must not import from web/
PROTECTED_PACKAGES = {
    "settings",
    "utilities",
    "security",
    "config",
}

# Existing violations that are allowlisted (file path substring -> allowed import patterns)
ALLOWLIST = {
    "settings/manager.py": [
        "web.models.settings",
        "web.themes",
        "web.services.socket_service",
    ],
    "utilities/log_utils.py": [
        "web.services.socket_service",
    ],
    "security/rate_limiter.py": [
        "web.server_config",
    ],
}

# Match import statements that reference .web. or from ..web
WEB_IMPORT_PATTERN = re.compile(
    r"^\s*(?:from\s+(?:\.+)?(?:local_deep_research\.)?web\b|"
    r"import\s+(?:local_deep_research\.)?web\b)"
)


def get_package(filepath):
    """Extract the package name from file path."""
    parts = filepath.replace("\\", "/").split("/")
    try:
        ldr_idx = parts.index("local_deep_research")
    except ValueError:
        return None
    if ldr_idx + 1 < len(parts) and parts[ldr_idx + 1] in PROTECTED_PACKAGES:
        return parts[ldr_idx + 1]
    return None


def is_allowlisted(filepath, line):
    """Check if a specific import is in the allowlist."""
    for path_substr, allowed_imports in ALLOWLIST.items():
        if path_substr in filepath:
            for allowed in allowed_imports:
                if allowed in line:
                    return True
    return False


def is_type_checking_block(lines, lineno):
    """Simple heuristic: check if line is inside a TYPE_CHECKING block."""
    for i in range(lineno - 1, max(0, lineno - 20), -1):
        stripped = lines[i].strip()
        if stripped.startswith("if TYPE_CHECKING"):
            return True
        if (
            stripped
            and not stripped.startswith("#")
            and not stripped.startswith("from")
            and not stripped.startswith("import")
        ):
            break
    return False


def check_file(filepath):
    errors = []
    try:
        with open(filepath, encoding="utf-8") as f:
            lines = f.readlines()
    except (OSError, UnicodeDecodeError):
        return errors

    pkg = get_package(filepath)
    if not pkg:
        return errors

    for lineno, line in enumerate(lines):
        if WEB_IMPORT_PATTERN.search(line):
            if is_allowlisted(filepath, line):
                continue
            if is_type_checking_block(lines, lineno):
                continue
            errors.append((lineno + 1, line.rstrip()))
    return errors


def main():
    exit_code = 0
    for filepath in sys.argv[1:]:
        if not filepath.endswith(".py"):
            continue
        errors = check_file(filepath)
        for lineno, line in errors:
            pkg = get_package(filepath)
            print(
                f"{filepath}:{lineno}: {pkg}/ must not import from web/ — "
                f"this breaks CLI/MCP/API usage"
            )
            print(f"  {line.strip()}")
            exit_code = 1
    if exit_code:
        print(
            "\nInfrastructure packages (settings/, utilities/, security/, config/) "
            "should not depend on the web layer."
        )
        print(
            "Move shared types to a common module or use dependency injection."
        )
    return exit_code


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