"""House account: the bot's own balance, fed by fines and lost bets.""" from __future__ import annotations from .. import pb_client from ..pb_client import DatabaseError from .store import _log, _now, get_user, _commit # --------------------------------------------------------------------------- # House account (bot user) # --------------------------------------------------------------------------- HOUSE_ID: int | None = None _house_pb_id: str | None = None def set_house(user_id: int) -> None: """Register the bot's Discord user ID as the house account.""" global HOUSE_ID, _house_pb_id if HOUSE_ID != user_id: _house_pb_id = None HOUSE_ID = user_id async def _house_record_id() -> str | None: """PocketBase record id of the house account (cached; creates the record on first use).""" global _house_pb_id if HOUSE_ID is None: return None if _house_pb_id is None: house = await get_user(HOUSE_ID) _house_pb_id = house.get("_pb_id") # type: ignore[typeddict-item] return _house_pb_id async def _credit_house(amount: int) -> None: """Add `amount` coins to the house via an atomic PocketBase increment. Deliberately lock-free: callers hold per-user locks, so this must never acquire one itself (see the locking rules above).""" if amount <= 0: return record_id = await _house_record_id() if record_id is None: return await pb_client.update_record(record_id, {"balance+": amount}) async def get_heist_global_cd() -> float: """Return unix timestamp until which no new heist can start. Persisted on house record.""" if HOUSE_ID is None: return 0.0 house = await get_user(HOUSE_ID) return float(house.get("heist_global_cd_until") or 0) async def set_heist_global_cd(until: float) -> None: """Persist heist global cooldown expiry to the house account in PocketBase.""" record_id = await _house_record_id() if record_id is None: return await pb_client.update_record(record_id, {"heist_global_cd_until": until}) async def _refund_house_safe(amount: int, context: str, related_uid: int) -> None: """Best-effort refund of `amount` to the house. Logs critical if it fails.""" if HOUSE_ID is None or amount <= 0: return try: await _credit_house(amount) except DatabaseError as exc: _log.critical( "House compensation failed (%s, related uid %s, amount %s): %s", context, related_uid, amount, exc, ) async def _refund_user_safe(_unused_house_id, amount: int, context: str, uid: int) -> None: """Best-effort atomic debit of `amount` from the house (compensates a failed user fine). Logs critical if it fails.""" if HOUSE_ID is None or amount <= 0: return try: record_id = await _house_record_id() if record_id: await pb_client.update_record(record_id, {"balance-": amount}) except DatabaseError as exc: _log.critical( "House debit compensation failed (%s, related uid %s, amount %s): %s", context, uid, amount, exc, )