"""
This module defines the Vulnerability class, which represents a generic vulnerability.
"""

import datetime
from typing import Any

from euvd.models._basevulnerability import _BaseVulnerability
from euvd.models.basescore import BaseScore
from euvd.models.customfieldtypes import EUVDIdType
from euvd.models.enisaidproductref import EnisaIdProductRef
from euvd.models.enisaidvendorref import EnisaIdVendorRef


class Vulnerability(_BaseVulnerability):
    """
    Encapsulates a generic vulnerability.
    """

    id: str
    enisa_id: EUVDIdType | None = None
    status: str | None = None  # TODO: Enumeration?

    def __hash__(self) -> int:
        return hash(
            (
                self.id,
                self.enisa_id,
            )
        )

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "Vulnerability":
        """
        Parses a vulnerability dictionary into a Vulnerability instance.

        Args:
            data (dict[str, Any]): The vulnerability data to parse.

        Returns:
            Vulnerability: An instance of the Vulnerability class.

        Raises:
            ValueError: If parsing fails due to invalid data.
        """
        try:
            return Vulnerability(
                id=data["id"],
                enisa_id=data.get("enisa_id"),
                description=data["description"],
                date_published=datetime.datetime.strptime(
                    data["datePublished"],
                    "%b %d, %Y, %I:%M:%S %p",
                ),
                date_updated=datetime.datetime.strptime(
                    data["dateUpdated"],
                    "%b %d, %Y, %I:%M:%S %p",
                ),
                status=data.get("status"),
                base_score=BaseScore(
                    score=data.get("baseScore", 0.0),
                    version=data.get("baseScoreVersion", "2"),
                    vector=data.get("baseScoreVector"),
                )
                if data.get("baseScore", -1.0) >= 0
                else None,
                references=set(filter(None, data.get("references", "").strip().split("\n"))),
                aliases=set(filter(None, data.get("aliases", "").strip().split("\n"))),
                assigner=data["assigner"],
                epss=data.get("epss"),
                products=set(
                    map(
                        EnisaIdProductRef.from_dict,
                        data.get("vulnerabilityProduct", []),
                    )
                ),
                vendors=set(map(EnisaIdVendorRef.from_dict, data.get("vulnerabilityVendor", []))),
            )
        except Exception as e:
            raise ValueError(f"Failed to parse vulnerability: {data}") from e


__all__ = [
    "Vulnerability",
]
