from __future__ import annotations import json from datetime import datetime, timezone from pathlib import Path from typing import Any from paths import DATA_DIR STATE_FILE = DATA_DIR / "state.json" def _now_iso() -> str: return datetime.now(timezone.utc).isoformat() def load_state() -> dict[str, Any]: if not STATE_FILE.exists(): return {} try: return json.loads(STATE_FILE.read_text(encoding="utf-8")) except (json.JSONDecodeError, OSError): return {} def save_state(state: dict[str, Any]) -> None: STATE_FILE.write_text( json.dumps(state, ensure_ascii=False, indent=2), encoding="utf-8", ) def get_pts_session() -> dict[str, Any] | None: state = load_state() session = state.get("pts_session") return session if isinstance(session, dict) else None def set_pts_session(session: dict[str, Any]) -> None: state = load_state() state["pts_session"] = session state["pts_session_updated_at"] = _now_iso() save_state(state) def clear_pts_session() -> None: state = load_state() state.pop("pts_session", None) state.pop("pts_session_updated_at", None) save_state(state) def get_teams_browser_meta() -> dict[str, Any]: state = load_state() meta = state.get("teams_browser") return meta if isinstance(meta, dict) else {} def set_teams_browser_meta(meta: dict[str, Any]) -> None: state = load_state() state["teams_browser"] = meta state["teams_browser_updated_at"] = _now_iso() save_state(state) def clear_teams_browser_meta() -> None: state = load_state() state.pop("teams_browser", None) state.pop("teams_browser_updated_at", None) save_state(state) def get_last_entries() -> list[dict[str, Any]]: state = load_state() entries = state.get("last_entries") return entries if isinstance(entries, list) else [] def set_last_entries(entries: list[dict[str, Any]]) -> None: state = load_state() state["last_entries"] = entries state["last_entries_updated_at"] = _now_iso() save_state(state) def get_filled_dates() -> set[str]: state = load_state() dates = state.get("filled_dates") if not isinstance(dates, list): return set() return set(dates) def mark_dates_filled(dates: list[str]) -> None: state = load_state() existing = set(state.get("filled_dates") or []) existing.update(dates) state["filled_dates"] = sorted(existing) save_state(state) def get_graph_session() -> dict[str, Any] | None: state = load_state() session = state.get("graph_session") return session if isinstance(session, dict) else None def set_graph_session(session: dict[str, Any]) -> None: state = load_state() state["graph_session"] = session state["graph_session_updated_at"] = _now_iso() save_state(state) def clear_graph_session() -> None: state = load_state() state.pop("graph_session", None) state.pop("graph_session_updated_at", None) save_state(state) def get_graph_device_auth() -> dict[str, Any] | None: state = load_state() pending = state.get("graph_device_auth") return pending if isinstance(pending, dict) else None def set_graph_device_auth(payload: dict[str, Any]) -> None: state = load_state() state["graph_device_auth"] = payload save_state(state) def clear_graph_device_auth() -> None: state = load_state() state.pop("graph_device_auth", None) save_state(state)