from typing import Protocol from app.repositories.protocols import IUserRepository class IReferralPayloadParser(Protocol): """Parse Telegram deep-link payload (e.g. `ref_ABC123`) into internal referrer key.""" def parse(self, raw: str | None) -> str | None: ... class DefaultReferralPayloadParser: """Placeholder: expects `ref_`; extend with signed tokens or DB lookup later.""" PREFIX = "ref_" def parse(self, raw: str | None) -> str | None: if not raw: return None if raw.startswith(self.PREFIX): return raw[len(self.PREFIX) :].strip() or None return None class ReferralService: """ Resolves referral payloads to referrer user rows. Placeholder: code is treated as referrer's telegram_id string for demo wiring; replace with dedicated referral codes table or signed deep links in production. """ def __init__( self, users: IUserRepository, parser: IReferralPayloadParser | None = None, ) -> None: self._users = users self._parser = parser or DefaultReferralPayloadParser() async def resolve_referrer_id( self, start_payload: str | None, *, invitee_telegram_id: int, ) -> int | None: code = self._parser.parse(start_payload) if not code: return None # Placeholder: interpret code as referrer's telegram_id (digits only). if not code.isdigit(): return None referrer = await self._users.get_by_telegram_id(int(code)) if referrer is None: return None if referrer.telegram_id == invitee_telegram_id: return None return referrer.id