"""Slow sources must not undo fast ones — run: python tests/test_reopen_grace.py

The three inventories see different moments in time. Wazuh syscollector is
close to live, Intune depends on the tenant's refresh policy, Defender TVM's
software list trails by days. After patching a host the fast source closes the
finding, then the slow source runs on its older picture and reopens it — every
night, forever, with a change history that describes our polling rather than
the host.
"""
import os
import sys
from datetime import datetime, timedelta

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from app.models.vulnerability import Vulnerability, VulnerabilityStatus, VulnerabilitySeverity
from app.services.audit_events import reopen_if_patched


class _NoDb:
    """reopen_if_patched only touches the db for the audit row, which is
    wrapped in try/except — so a stub is enough to exercise the decision."""
    def add(self, *a, **k): pass
    def query(self, *a, **k): raise RuntimeError("no db in this test")


def _patched(ago):
    return Vulnerability(cve_id="CVE-X", severity=VulnerabilitySeverity.high,
                         status=VulnerabilityStatus.patched,
                         patched_at=datetime.now() - ago)


def demo():
    db = _NoDb()

    # Defender still holding a days-old picture must not reopen a fresh close.
    v = _patched(timedelta(hours=6))
    assert reopen_if_patched(db, v, reason="r", source="defender") is False
    assert v.status == VulnerabilityStatus.patched

    # Past its lag, Defender is believed again — the host may really have
    # regressed, and refusing forever would hide a genuine reopen.
    v = _patched(timedelta(days=4))
    assert reopen_if_patched(db, v, reason="r", source="defender") is True
    assert v.status == VulnerabilityStatus.open

    # Intune's window is shorter than Defender's.
    v = _patched(timedelta(hours=6))
    assert reopen_if_patched(db, v, reason="r", source="intune") is False
    v = _patched(timedelta(days=2))
    assert reopen_if_patched(db, v, reason="r", source="intune") is True

    # Sources reading a live inventory get no grace at all.
    for src in ("wazuh_sync", "app_scan", "msrc", "nessus_sync"):
        v = _patched(timedelta(minutes=1))
        assert reopen_if_patched(db, v, reason="r", source=src) is True, src

    # An already-open finding is never touched, whatever the source.
    v = Vulnerability(cve_id="CVE-Y", severity=VulnerabilitySeverity.low,
                      status=VulnerabilityStatus.open)
    assert reopen_if_patched(db, v, reason="r", source="defender") is False

    print("reopen grace OK")


if __name__ == "__main__":
    demo()
