"""Dependencies Collector — discovers manifests and queries OSV for vulnerabilities."""

from __future__ import annotations

from pathlib import Path
from typing import Any

from sentinel.collectors.base import BaseCollector
from sentinel.collectors.deps.osv_client import query_osv
from sentinel.collectors.deps.parsers import cargo, golang, npm, pip, ruby
from sentinel.models.config import DepsConfig

ECOSYSTEM_PARSERS = {
    "npm": npm.parse,
    "pip": pip.parse,
    "go": golang.parse,
    "cargo": cargo.parse,
    "ruby": ruby.parse,
}

# Sentinel ecosystem name → OSV ecosystem identifier
OSV_ECOSYSTEM_MAP = {
    "npm": "npm",
    "pip": "PyPI",
    "go": "Go",
    "cargo": "crates.io",
    "ruby": "RubyGems",
}


class DepsCollector(BaseCollector):
    module_name = "deps"

    def __init__(self, repo_path: Path, config: DepsConfig) -> None:
        super().__init__(repo_path)
        self.config = config

    def collect(self) -> dict[str, Any]:
        ecosystem_results: list[dict[str, Any]] = []
        query_packages: list[dict[str, str]] = []

        for ecosystem in self.config.ecosystems:
            parser = ECOSYSTEM_PARSERS.get(ecosystem)
            if not parser:
                continue
            parsed = parser(self.repo_path)
            if not parsed.get("found"):
                continue
            ecosystem_results.append(parsed)

            osv_eco = OSV_ECOSYSTEM_MAP.get(ecosystem, ecosystem)
            for pkg in parsed.get("packages", []):
                ver = pkg.get("resolved_version") or pkg.get("version_spec", "")
                # Only query packages with a concrete version (no range specifiers)
                if ver and not any(c in ver for c in ("^", "~", "*", ">=", "<=", ">", "<")):
                    query_packages.append({
                        "name": pkg["name"],
                        "version": ver,
                        "ecosystem": osv_eco,
                        "source_ecosystem": ecosystem,
                    })

        # Batch CVE lookup via OSV.dev
        vuln_results: list[dict[str, Any]] = []
        if query_packages:
            osv_responses = query_osv(query_packages)
            for pkg, vulns in zip(query_packages, osv_responses):
                if vulns:
                    vuln_results.append({"package": pkg, "vulns": vulns})

        return {
            "ecosystems_found": ecosystem_results,
            "vulnerabilities": vuln_results,
            "ignore_cves": self.config.ignore_cves,
        }
