import re
from typing import List, Tuple
from models.vulnerability import Vulnerability
from models.vulnerability_intelligence import VulnerabilityIntelligence
from services.vulnerabilities.validators.vulnerability_validator import VulnerabilityValidator
from services.vulnerability_intelligence.factories.vulnerability_intelligence_factory import VulnerabilityIntelligenceFactory

class VulnerabilityIntelligenceProcessor:
    @staticmethod
    def process(vulnerabilities: List[Vulnerability], search_terms: List[str]) -> List[VulnerabilityIntelligence]:
        validated_vulnerabilities = [
            vuln for vuln in vulnerabilities if VulnerabilityValidator.validate_with_versions(search_terms, vuln)
        ]
        unique_vulnerabilities = VulnerabilityIntelligenceProcessor._remove_duplicates(validated_vulnerabilities)
        remapped_moderate_to_medium = VulnerabilityIntelligenceProcessor._remapped_moderate_to_medium(unique_vulnerabilities)
        
        sorted_vulnerabilities = VulnerabilityIntelligenceProcessor._sort_by_id(remapped_moderate_to_medium)

        vulnerability_intelligence_list = VulnerabilityIntelligenceFactory.make(sorted_vulnerabilities)

        return vulnerability_intelligence_list

    @staticmethod
    def _remove_duplicates(vulnerabilities: List[Vulnerability]) -> List[Vulnerability]:
        seen = set()
        unique_vulnerabilities = []

        for vuln in vulnerabilities:
            vuln_tuple = (
                vuln.id, vuln.source, vuln.url, tuple(vuln.reference_urls),
                vuln.base_score, vuln.base_severity, vuln.title, vuln.description,
                tuple(vuln.vulnerable_components), tuple(vuln.tags),
                tuple(vuln.weaknesses),
            )

            if vuln_tuple not in seen:
                seen.add(vuln_tuple)
                unique_vulnerabilities.append(vuln)

        return unique_vulnerabilities
    
    
    @staticmethod
    def _remapped_moderate_to_medium(vulnerabilities: List[Vulnerability]) -> List[Vulnerability]:
        remapped = []
        for vuln in vulnerabilities:
            if vuln.base_severity.lower() == "moderate":
                vuln.base_severity = "Medium" 
                remapped.append(vuln)
            else:
                remapped.append(vuln)

        return remapped


    @staticmethod
    def _sort_by_id(vulnerabilities: List[Vulnerability]) -> List[Vulnerability]:
        def extract_year_and_numeric_id(vuln_id: str) -> Tuple[int, int]:
            match = re.match(r"CVE-(\d+)-(\d+)", vuln_id)
            if match:
                year = int(match.group(1))
                numeric_id = int(match.group(2))
                return year, numeric_id
            return 0, 0

        return sorted(vulnerabilities, key=lambda vuln: extract_year_and_numeric_id(vuln.id))
