"""Group duty pin: current duty message text, next shift end, pin CRUD. All accept session.""" from datetime import datetime, timezone from zoneinfo import ZoneInfo from sqlalchemy.orm import Session from duty_teller.db.repository import ( get_current_duty, get_next_shift_end, get_group_duty_pin, save_group_duty_pin, delete_group_duty_pin, get_all_group_duty_pin_chat_ids, ) def format_duty_message(duty, user, tz_name: str) -> str: """Build the text for the pinned message. duty, user may be None.""" if duty is None or user is None: return "Сейчас дежурства нет." try: tz = ZoneInfo(tz_name) except Exception: tz = ZoneInfo("Europe/Moscow") tz_name = "Europe/Moscow" start_dt = datetime.fromisoformat(duty.start_at.replace("Z", "+00:00")) end_dt = datetime.fromisoformat(duty.end_at.replace("Z", "+00:00")) start_local = start_dt.astimezone(tz) end_local = end_dt.astimezone(tz) offset_sec = ( start_local.utcoffset().total_seconds() if start_local.utcoffset() else 0 ) sign = "+" if offset_sec >= 0 else "-" h, r = divmod(abs(int(offset_sec)), 3600) m = r // 60 tz_hint = f"UTC{sign}{h:d}:{m:02d}, {tz_name}" time_range = ( f"{start_local.strftime('%d.%m.%Y %H:%M')} — " f"{end_local.strftime('%d.%m.%Y %H:%M')} ({tz_hint})" ) lines = [ f"🕐 Дежурство: {time_range}", f"👤 {user.full_name}", ] if user.phone: lines.append(f"📞 {user.phone}") if user.username: lines.append(f"@{user.username}") return "\n".join(lines) def get_duty_message_text(session: Session, tz_name: str) -> str: """Get current duty from DB and return formatted message.""" now = datetime.now(timezone.utc) result = get_current_duty(session, now) if result is None: return "Сейчас дежурства нет." duty, user = result return format_duty_message(duty, user, tz_name) def get_next_shift_end_utc(session: Session) -> datetime | None: """Return next shift end as naive UTC datetime for job scheduling.""" return get_next_shift_end(session, datetime.now(timezone.utc)) def save_pin(session: Session, chat_id: int, message_id: int) -> None: """Save or update the pinned message record for a chat.""" save_group_duty_pin(session, chat_id, message_id) def delete_pin(session: Session, chat_id: int) -> None: """Remove the pinned message record when the bot leaves the group.""" delete_group_duty_pin(session, chat_id) def get_message_id(session: Session, chat_id: int) -> int | None: """Return message_id for the pin in this chat, or None.""" pin = get_group_duty_pin(session, chat_id) return pin.message_id if pin else None def get_all_pin_chat_ids(session: Session) -> list[int]: """Return all chat_ids that have a pinned duty message (for restoring jobs on startup).""" return get_all_group_duty_pin_chat_ids(session)