import re

from typing import Tuple, Dict
from .common.enums import DetailType
from .patterns import STARTING_DETAILS_MAPPING, WEAKNESS_PATTERNS, CONFIGURATION_PATTERNS, COMPONENT_PATTERNS
from .patterns.common import REPLACEMENT_PHRASES, NOISE_PATTERNS


class CVEDriller:
    def __init__(self, verbose: bool = False):
        self.verbose = verbose

    def log_info(self, message: str):
        if self.verbose:
            print(message)

    def extract_from_patterns(self, desc: str, patterns: dict):
        for name, pattern in patterns.items():
            match = re.compile(pattern).match(desc)

            if match:
                self.log_info(f"{name} - {pattern}")
                return match.groupdict()

        return None

    @staticmethod
    def normalize_phrases(desc: str) -> str:
        if desc[-1] != '.':
            desc += '.'

        desc = re.sub(r'\s+', ' ', desc)
        desc = re.sub(r"\"", "", desc)

        for old, new in REPLACEMENT_PHRASES.items():
            desc = re.sub(old, new, desc)

        return desc

    @staticmethod
    def remove_noise(desc: str) -> str:
        for pattern in NOISE_PATTERNS:
            desc = re.sub(pattern, "", desc)

        return desc

    def __call__(self, desc: str) -> Tuple[DetailType | None, Dict[str, str] | None]:
        desc = desc.strip()
        desc = self.normalize_phrases(desc)
        desc = self.remove_noise(desc)

        self.log_info(f"Description: {desc}")
        for detail_type, pattern in STARTING_DETAILS_MAPPING.items():
            if re.match(pattern, desc):
                self.log_info(f"Found starting pattern: {detail_type}")

                if detail_type == DetailType.CONFIGURATION:
                    return DetailType.CONFIGURATION, self.extract_from_patterns(desc, CONFIGURATION_PATTERNS)
                elif detail_type == DetailType.COMPONENT:
                    return DetailType.COMPONENT, self.extract_from_patterns(desc, COMPONENT_PATTERNS)
                elif detail_type == DetailType.WEAKNESS:
                    return DetailType.WEAKNESS, self.extract_from_patterns(desc, WEAKNESS_PATTERNS)

        return None, None
