#!/usr/bin/env python3
"""
Pre-commit hook to check for external CDN and resource references.
Ensures all resources are served locally from vendor directories.
"""

import re
import sys
from pathlib import Path
from typing import List, Tuple

# Patterns that indicate external resources
EXTERNAL_PATTERNS = [
    # CDN URLs (with or without protocol)
    r"(https?://)?cdn\.(cloudflare|jsdelivr|unpkg|jspm|skypack)",
    r"(https?://)?cdnjs\.(cloudflare\.com|com)",
    r"(https?://)?unpkg\.(com|\.)",
    r"(https?://)?jsdelivr\.(net|com)",
    r"(https?://)?ajax\.googleapis\.",
    r"(https?://)?code\.jquery\.",
    r"(https?://)?maxcdn\.",
    r"(https?://)?stackpath\.",
    # Common external libraries
    r"https?://.*\/(jquery|bootstrap|react|vue|angular|fontawesome|font-awesome)[\-\.]",
    # Script/link tags with external sources (excluding vendor paths)
    r'<script[^>]+src=["\']https?://(?!localhost|127\.0\.0\.1)',
    r'<link[^>]+href=["\']https?://(?!localhost|127\.0\.0\.1)',
    # Integrity attributes (often used with CDNs)
    r'integrity=["\']sha(256|384|512)-',
    r'crossorigin=["\']anonymous["\']',
]

# Allowed external resources (APIs, documentation, etc)
ALLOWED_PATTERNS = [
    # API endpoints
    r"https?://api\.",
    r"https?://.*\.api\.",
    r"openrouter\.ai/api",
    # Documentation and source links
    r"https?://github\.com",
    r"https?://docs\.",
    r"https?://.*\.readthedocs\.",
    r"https?://npmjs\.com",
    r"https?://pypi\.org",
    # Example/placeholder URLs
    r"https?://example\.",
    r"https?://localhost",
    r"https?://127\.0\.0\.1",
    r"https?://0\.0\.0\.0",
    # Common in comments or documentation
    r"#.*https?://",
    r"//.*https?://",
    r"\*.*https?://",
]


def check_file(filepath: Path) -> List[Tuple[int, str, str]]:
    """
    Check a file for external resource references.

    Returns list of (line_number, line_content, pattern_matched) tuples.
    """
    violations = []

    try:
        with open(filepath, "r", encoding="utf-8") as f:
            lines = f.readlines()
    except (UnicodeDecodeError, IOError):
        # Skip binary files or files we can't read
        return violations

    for line_num, line in enumerate(lines, 1):
        # Check if line contains external patterns
        for pattern in EXTERNAL_PATTERNS:
            if re.search(pattern, line, re.IGNORECASE):
                # Check if it's an allowed exception
                is_allowed = False
                for allowed in ALLOWED_PATTERNS:
                    if re.search(allowed, line, re.IGNORECASE):
                        is_allowed = True
                        break

                if not is_allowed:
                    violations.append((line_num, line.strip(), pattern))
                    break  # Only report first matching pattern per line

    return violations


def main():
    """Main entry point for the pre-commit hook."""
    # Get list of files to check from command line arguments
    files = sys.argv[1:] if len(sys.argv) > 1 else []

    if not files:
        # If no files specified, check all relevant files
        patterns = ["**/*.html", "**/*.js", "**/*.css", "**/*.py"]
        files = []
        for pattern in patterns:
            files.extend(Path(".").glob(pattern))
    else:
        files = [Path(f) for f in files]

    all_violations = []

    for filepath in files:
        # Skip vendor directories and node_modules
        if any(
            part in filepath.parts
            for part in [
                "vendor",
                "node_modules",
                ".venv",
                "venv",
                "__pycache__",
            ]
        ):
            continue

        violations = check_file(filepath)
        if violations:
            all_violations.append((filepath, violations))

    if all_violations:
        print("\n❌ External resource references found!\n")
        print(
            "All resources should be served locally from the vendor directory."
        )
        print("Found the following external references:\n")

        for filepath, violations in all_violations:
            print(f"📄 {filepath}")
            for line_num, line_content, pattern in violations:
                print(f"  Line {line_num}: {line_content[:100]}...")
                print(f"    Matched pattern: {pattern}\n")

        print("\nTo fix this:")
        print("1. Add the library to package.json as a dependency")
        print("2. Run 'npm install' to download it")
        print("3. Update the reference to use the local node_modules path")
        print("4. Use a build process to bundle the assets")
        print(
            "\nAll external libraries should be managed through npm for security and version tracking."
        )
        return 1

    return 0


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