"""OpenSourceMalware enrichment: check packages for malicious content."""

from __future__ import annotations

import logging
import time
from typing import Any, Dict, Optional

try:
    from constants import Constants
    from common.logging_utils import extra_context, is_debug_enabled, Timer
    from registry.opensourcemalware.client import OpenSourceMalwareClient
except ImportError:
    from src.constants import Constants
    from src.common.logging_utils import extra_context, is_debug_enabled, Timer
    from src.registry.opensourcemalware.client import OpenSourceMalwareClient

logger = logging.getLogger(__name__)


def _merge_provenance(mp, osm_entry: Dict[str, Any]) -> None:
    """Merge OpenSourceMalware provenance into package provenance.

    Args:
        mp: MetaPackage instance
        osm_entry: OSM provenance dictionary
    """
    prov = getattr(mp, "provenance", None) or {}
    # Keep existing osm block, extend it
    osm_prev = prov.get("opensourcemalware", {})
    if isinstance(osm_prev, dict):
        # Merge shallowly
        for k, v in osm_entry.items():
            if k == "fields":
                fields_prev = osm_prev.get("fields", {})
                if not isinstance(fields_prev, dict):
                    fields_prev = {}
                if isinstance(v, dict):
                    fields_prev.update(v)
                osm_prev["fields"] = fields_prev
            else:
                osm_prev[k] = v
        prov["opensourcemalware"] = osm_prev
    else:
        prov["opensourcemalware"] = osm_entry
    mp.provenance = prov


def enrich_metapackage(
    mp,
    ecosystem: str,
    name: str,
    version: Optional[str],
    client: Optional[OpenSourceMalwareClient] = None,
) -> None:
    """Check package for malicious content and enrich MetaPackage.

    Args:
        mp: MetaPackage instance
        ecosystem: Package ecosystem (npm, pypi, maven, nuget, rubygems)
        name: Package name
        version: Optional concrete version string
        client: Optional OpenSourceMalwareClient (constructed if not provided)
    """
    if not getattr(Constants, "OSM_ENABLED", False):  # type: ignore[attr-defined]
        return

    try:
        with Timer() as t:
            if is_debug_enabled(logger):
                logger.debug(
                    "OpenSourceMalware enrichment start",
                    extra=extra_context(
                        event="osm_enrich_start",
                        component="osm_enrich",
                        ecosystem=ecosystem,
                        pkg=name,
                        version=version,
                    ),
                )

            c = client or OpenSourceMalwareClient()
            status, headers, response_json = c.check_package(ecosystem, name, version)

            osm_prov: Dict[str, Any] = {
                "api_url": f"{c.base_url}/check-package-malicious",
                "fetched_at_ts": int(time.time()),
                "fields": {},
                "http": {
                    "status": status,
                },
            }

            if status == 200 and isinstance(response_json, dict):
                # Parse response
                malicious = response_json.get("malicious", False)
                threat_count = response_json.get("threat_count", 0)
                details = response_json.get("details") or {}
                reason = (details.get("description") if isinstance(details, dict) else None) or response_json.get("message", "")
                severity = details.get("severity_level") if isinstance(details, dict) else None

                # Set MetaPackage fields
                mp.osm_checked = True
                mp.osm_malicious = bool(malicious)
                if malicious:
                    mp.osm_reason = reason if reason else "Package flagged as malicious"
                    mp.osm_threat_count = int(threat_count) if threat_count else 0
                    mp.osm_severity = severity if severity else None
                else:
                    mp.osm_reason = None
                    mp.osm_threat_count = 0
                    mp.osm_severity = None

                # Store provenance
                osm_prov["fields"] = {
                    "malicious": malicious,
                    "threat_count": threat_count,
                    "details": details,
                    "package_name": response_json.get("package_name"),
                    "ecosystem": response_json.get("ecosystem"),
                    "version": response_json.get("version"),
                }

                if is_debug_enabled(logger):
                    logger.debug(
                        "OpenSourceMalware check result",
                        extra=extra_context(
                            event="osm_check",
                            component="osm_enrich",
                            ecosystem=ecosystem,
                            pkg=name,
                            version=version,
                            malicious=malicious,
                            threat_count=threat_count,
                            status=status,
                        ),
                    )
            else:
                # API error or non-200 response
                mp.osm_checked = True
                mp.osm_malicious = None  # Unknown
                mp.osm_reason = None
                mp.osm_threat_count = None
                mp.osm_severity = None

                if status != 200:
                    logger.debug(
                        "OpenSourceMalware API error",
                        extra=extra_context(
                            event="osm_error",
                            component="osm_enrich",
                            ecosystem=ecosystem,
                            pkg=name,
                            version=version,
                            status=status,
                        ),
                    )

            # Merge provenance
            _merge_provenance(mp, osm_prov)

            if is_debug_enabled(logger):
                logger.debug(
                    "OpenSourceMalware enrichment completed",
                    extra=extra_context(
                        event="osm_enrich_complete",
                        component="osm_enrich",
                        outcome="success",
                        duration_ms=t.duration_ms(),
                        ecosystem=ecosystem,
                        pkg=name,
                        version=version,
                    ),
                )
    except Exception as exc:  # pylint: disable=broad-exception-caught
        # Never fail the pipeline due to OSM issues
        logger.warning(
            "OpenSourceMalware enrichment error: %s",
            str(exc),
            extra=extra_context(
                event="osm_error",
                component="osm_enrich",
                outcome="exception",
                error_message=str(exc),
                ecosystem=ecosystem,
                pkg=name,
                version=version,
            ),
        )
        # Set checked but unknown
        mp.osm_checked = True
        mp.osm_malicious = None
        mp.osm_reason = None
        mp.osm_threat_count = None
        mp.osm_severity = None
