# ui/globe_commands.py from __future__ import annotations from typing import Any from ui.country_coords import resolve_countries def empty_globe_state() -> dict[str, Any]: return { "version": 0, "details_version": 0, "markers": [], "highlights": [], "fly_to": None, "country_details": {}, } def _next_version(state: dict[str, Any]) -> int: return int(state.get("version", 0)) + 1 def _marker_payload( country: dict[str, Any], *, country_details: dict[str, Any] | None = None, ) -> dict[str, Any]: payload = { "iso2": country["iso2"], "name": country.get("name"), "label": country["label"], "lng": country["lng"], "lat": country["lat"], } if country_details: detail = country_details.get(country["iso2"]) if detail: payload["detail"] = detail return payload def _highlight_payload(country: dict[str, Any]) -> dict[str, Any]: return { "iso2": country["iso2"], "lng": country["lng"], "lat": country["lat"], } def _fly_to_payload( countries: list[dict[str, Any]], *, zoom: float | None, ) -> dict[str, Any] | None: if not countries: return None if len(countries) == 1: country = countries[0] return { "center": [country["lng"], country["lat"]], "zoom": zoom if zoom is not None else 4.0, } lngs = [country["lng"] for country in countries] lats = [country["lat"] for country in countries] return { "bounds": [[min(lngs), min(lats)], [max(lngs), max(lats)]], "padding": 80, } def apply_update_globe( state: dict[str, Any], args: dict[str, Any], ) -> tuple[dict[str, Any], dict[str, Any]]: action = (args.get("action") or "show").strip().lower() countries = args.get("countries") or [] labels = args.get("labels") zoom = args.get("zoom") if action == "clear": new_state = empty_globe_state() new_state["version"] = _next_version(state) return {"status": "cleared", "action": action}, new_state if not countries: return ( {"error": "countries is required unless action is clear"}, state, ) resolved, unknown = resolve_countries(countries, labels) if not resolved: return ( { "error": "No valid ISO-2 country codes were provided", "unknown_codes": unknown, }, state, ) country_details = dict(state.get("country_details") or {}) new_state = { "version": _next_version(state), "details_version": int(state.get("details_version", 0)), "markers": list(state.get("markers", [])), "highlights": list(state.get("highlights", [])), "fly_to": state.get("fly_to"), "country_details": country_details, } if action == "show": new_state["markers"] = [ _marker_payload(country, country_details=country_details) for country in resolved ] new_state["highlights"] = [_highlight_payload(country) for country in resolved] new_state["fly_to"] = _fly_to_payload(resolved, zoom=zoom) elif action in {"markers", "add_markers"}: existing = {marker["iso2"] for marker in new_state["markers"]} for country in resolved: if country["iso2"] not in existing: new_state["markers"].append( _marker_payload(country, country_details=country_details) ) elif action == "highlight": existing = {item["iso2"] for item in new_state["highlights"]} for country in resolved: if country["iso2"] not in existing: new_state["highlights"].append(_highlight_payload(country)) elif action == "fly_to": new_state["fly_to"] = _fly_to_payload(resolved, zoom=zoom) else: return ( { "error": ( "Unknown action. Use show, markers, highlight, fly_to, or clear." ) }, state, ) result: dict[str, Any] = { "status": "ok", "action": action, "countries": [ { "iso2": country["iso2"], "name": country["name"], "label": country["label"], } for country in resolved ], } if unknown: result["unknown_codes"] = unknown return result, new_state