"""Curated OSINT conflict-zone catalog + point-in-bbox event counting. A static, human-curated list of active conflict theatres (war / high / elevated). Purely descriptive — this is a catalog, not a live feed and not a scrape of LiveUAMap or any other source. Severity and descriptions are editorial judgement kept short and factual. Each zone carries an internal ``bbox`` (``min_lat, min_lon, max_lat, max_lon``) used only to count pre-existing geocoded news/GDELT/``/api/news/map`` rows that fall inside it. The bbox is not part of the API response; callers get the ``eventCount`` roll-up instead. Never call an upstream API from here — event counts come from rows already in the local database (``events`` with geocoords + ``news_items`` map pins). """ from __future__ import annotations from datetime import datetime # id → zone. ``lat``/``lon`` is the fly-to anchor; ``bbox`` is the internal # count window in ``min_lat, min_lon, max_lat, max_lon`` order. _ZONES: tuple[dict, ...] = ( { "id": "ukraine", "label": "Ukraine", "severity": "war", "lat": 48.5, "lon": 31.0, "description": "Full-scale Russian invasion since 2022; active front lines in the east and south.", "bbox": (44.3, 22.1, 52.4, 40.2), }, { "id": "gaza", "label": "Gaza", "severity": "war", "lat": 31.4, "lon": 34.4, "description": "Israel–Hamas war; sustained fighting and a severe humanitarian crisis in the Gaza Strip.", "bbox": (31.0, 34.1, 31.8, 34.7), }, { "id": "sudan", "label": "Sudan", "severity": "war", "lat": 15.5, "lon": 30.0, "description": "Civil war between the SAF and RSF since 2023, with mass displacement across the country.", "bbox": (8.7, 21.8, 22.0, 38.6), }, { "id": "myanmar", "label": "Myanmar", "severity": "war", "lat": 21.5, "lon": 96.0, "description": "Post-2021 coup conflict pitting the junta against resistance and ethnic armed groups.", "bbox": (9.5, 92.2, 28.5, 101.2), }, { "id": "drc", "label": "DR Congo", "severity": "war", "lat": -1.5, "lon": 28.0, "description": "Eastern DRC conflict involving M23 and other armed groups; heavy displacement around Goma.", "bbox": (-5.0, 26.0, 3.0, 31.0), }, { "id": "yemen", "label": "Yemen", "severity": "war", "lat": 15.5, "lon": 47.5, "description": "Protracted Houthi–government/coalition war with one of the world's worst humanitarian emergencies.", "bbox": (12.6, 42.5, 19.0, 54.0), }, { "id": "syria", "label": "Syria", "severity": "war", "lat": 34.5, "lon": 38.5, "description": "Multi-sided civil war; government, opposition, and external actors continue to engage.", "bbox": (32.3, 35.7, 37.3, 42.4), }, { "id": "lebanon", "label": "Lebanon", "severity": "high", "lat": 33.9, "lon": 35.9, "description": "Israel–Hezbollah hostilities with periodic escalation along the southern border.", "bbox": (33.0, 35.0, 34.7, 36.6), }, { "id": "sahel", "label": "Sahel", "severity": "high", "lat": 14.5, "lon": 0.0, "description": "Jihadist insurgencies across Mali, Burkina Faso, and Niger destabilising the central Sahel.", "bbox": (10.0, -10.0, 20.0, 12.0), }, { "id": "somalia", "label": "Somalia", "severity": "high", "lat": 6.0, "lon": 45.0, "description": "Al-Shabaab insurgency against the federal government and security forces.", "bbox": (-2.0, 41.0, 12.0, 51.5), }, { "id": "red_sea", "label": "Red Sea", "severity": "high", "lat": 18.0, "lon": 40.0, "description": "Houthi attacks on commercial shipping transiting the Red Sea corridor.", "bbox": (12.0, 34.0, 22.0, 44.0), }, { "id": "taiwan_strait", "label": "Taiwan Strait", "severity": "elevated", "lat": 24.5, "lon": 119.5, "description": "Heightened military standoff between China and Taiwan, including deterrence patrols.", "bbox": (21.9, 117.0, 26.5, 122.0), }, { "id": "korean_dmz", "label": "Korean DMZ", "severity": "elevated", "lat": 38.3, "lon": 127.0, "description": "Heavily fortified inter-Korean border with periodic tensions and military drills.", "bbox": (37.5, 126.0, 39.0, 128.5), }, ) SEVERITIES: frozenset[str] = frozenset({"war", "high", "elevated"}) def conflict_zones() -> list[dict]: """Return a fresh shallow copy of the catalog (callers must not mutate).""" return [dict(z) for z in _ZONES] def zone_event_stats( points: list[tuple[float, float, datetime | None]], bbox: tuple[float, float, float, float], ) -> tuple[int, datetime | None]: """Count points inside ``bbox`` and return (count, latest timestamp). ``points`` is an iterable of ``(lat, lon, ts)``; ``ts`` may be ``None``. ``bbox`` is ``(min_lat, min_lon, max_lat, max_lon)``. """ min_lat, min_lon, max_lat, max_lon = bbox count = 0 latest: datetime | None = None for lat, lon, ts in points: if min_lat <= lat <= max_lat and min_lon <= lon <= max_lon: count += 1 if ts is not None and (latest is None or ts > latest): latest = ts return count, latest