from unittest.mock import MagicMock

from sator_core.models.product import Product, Configuration
from sator_core.models.vulnerability import VulnerabilityLocator, VulnerabilityAttributes
from sator_core.use_cases.analysis.attributes.vulnerability import VulnerabilityAttributesAnalysis


existing_vuln_attrs = VulnerabilityAttributes(
    weakness="out of bounds memory access",
    configuration="ONLYOFFICE DocumentServer 4.0.3 through 7.3.2",
    attacker="remote attackers",
    impact="run arbitrary code",
    vector="crafter JavaScript file",
)

existing_product = Product(name="onlyoffice", vendor="document_server")
existing_config = Configuration(product=existing_product, version="4.0.3")
existing_locator = VulnerabilityLocator(product=existing_product, version=existing_config.version)


def test_returns_existing_vulnerability_locator():
    storage_mock = MagicMock()
    product_repo_mock = MagicMock()

    storage_mock.load.side_effect = [existing_locator]  # simulate first load returns locator

    analyzer = VulnerabilityAttributesAnalysis([product_repo_mock], storage_mock)
    result = analyzer.analyze_vulnerability_attributes("CVE-2023-30187")

    assert result == existing_locator
    storage_mock.load.assert_called_once_with(VulnerabilityLocator, "CVE-2023-30187")


def test_creates_locator_from_attributes_and_repo():
    storage_mock = MagicMock()
    product_repo_mock = MagicMock()

    # No locator initially
    storage_mock.load.side_effect = [None, existing_vuln_attrs]

    # Mock product repo search
    product_repo_mock.search_config_by_str.return_value = MagicMock(
        product=existing_product, version=existing_config.version
    )

    analyzer = VulnerabilityAttributesAnalysis([product_repo_mock], storage_mock)
    result = analyzer.analyze_vulnerability_attributes("CVE-2023-30187")

    assert result.product == existing_product
    assert result.version == existing_config.version
    assert result.function is None
    assert result.file is None

    storage_mock.save.assert_called_once()


def test_returns_none_if_no_locator_or_config_found():
    storage_mock = MagicMock()
    product_repo_mock = MagicMock()

    storage_mock.load.side_effect = [None, VulnerabilityAttributes(configuration="configY")]
    product_repo_mock.search_config_by_str.return_value = None

    analyzer = VulnerabilityAttributesAnalysis([product_repo_mock], storage_mock)
    result = analyzer.analyze_vulnerability_attributes("vuln-789")

    assert result is None
