from __future__ import annotations from collections.abc import Callable from datetime import UTC, datetime from decimal import Decimal from uuid import uuid4 import pytest from pytest import FixtureRequest as Request from generalresearch.currency import USDCent from generalresearch.managers.thl.contest_manager import ContestManager from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager from generalresearch.models.thl.contest.contest import Contest from generalresearch.models.thl.contest.leaderboard import ( LeaderboardContestCreate, ) from generalresearch.models.thl.contest.milestone import ( MilestoneContestCreate, ) from generalresearch.models.thl.contest.raffle import ( RaffleContestCreate, ) from generalresearch.models.thl.product import Product from generalresearch.models.thl.user import User # === Miscellaneous === # === Managers === # === Models === @pytest.fixture def raffle_contest_create() -> RaffleContestCreate: from generalresearch.models.thl.contest import ( ContestEndCondition, ContestPrize, ) from generalresearch.models.thl.contest.definitions import ( ContestPrizeKind, ContestType, ) from generalresearch.models.thl.contest.raffle import ( ContestEntryType, RaffleContestCreate, ) # This is what we'll get from the fastapi endpoint return RaffleContestCreate( name="test", contest_type=ContestType.RAFFLE, entry_type=ContestEntryType.CASH, prizes=[ ContestPrize( name="iPod 64GB White", kind=ContestPrizeKind.PHYSICAL, estimated_cash_value=USDCent(100), ) ], end_condition=ContestEndCondition(target_entry_amount=USDCent(100)), ) @pytest.fixture def raffle_contest_in_db( product_user_wallet_yes: Product, raffle_contest_create: RaffleContestCreate, contest_manager: ContestManager, ) -> Contest: return contest_manager.create( product_id=product_user_wallet_yes.uuid, contest_create=raffle_contest_create ) @pytest.fixture def raffle_contest( product_user_wallet_yes: Product, raffle_contest_create: RaffleContestCreate ) -> Contest: from generalresearch.models.thl.contest.io import contest_create_to_contest return contest_create_to_contest( product_id=product_user_wallet_yes.uuid, contest_create=raffle_contest_create ) @pytest.fixture(scope="function") def raffle_contest_factory( product_user_wallet_yes: Product, raffle_contest_create: RaffleContestCreate, contest_manager: ContestManager, ) -> Callable[..., Contest]: def _inner(**kwargs): raffle_contest_create.update(**kwargs) return contest_manager.create( product_id=product_user_wallet_yes.uuid, contest_create=raffle_contest_create, ) return _inner @pytest.fixture def milestone_contest_create() -> MilestoneContestCreate: from generalresearch.models.thl.contest import ( ContestPrize, ) from generalresearch.models.thl.contest.definitions import ( ContestPrizeKind, ContestType, ) from generalresearch.models.thl.contest.milestone import ( ContestEntryTrigger, MilestoneContestCreate, MilestoneContestEndCondition, ) # This is what we'll get from the fastapi endpoint return MilestoneContestCreate( name="Win a 50% bonus for 7 days and a $1 bonus after your first 3 completes!", description="only valid for the first 5 users", contest_type=ContestType.MILESTONE, prizes=[ ContestPrize( name="50% for 7 days", kind=ContestPrizeKind.PROMOTION, estimated_cash_value=USDCent(0), ), ContestPrize( name="$1 Bonus", kind=ContestPrizeKind.CASH, cash_amount=USDCent(1_00), estimated_cash_value=USDCent(1_00), ), ], end_condition=MilestoneContestEndCondition( ends_at=datetime(year=2030, month=1, day=1, tzinfo=UTC), max_winners=5, ), entry_trigger=ContestEntryTrigger.TASK_COMPLETE, target_amount=3, ) @pytest.fixture def milestone_contest_in_db( product_user_wallet_yes: Product, milestone_contest_create: MilestoneContestCreate, contest_manager: ContestManager, ) -> Contest: return contest_manager.create( product_id=product_user_wallet_yes.uuid, contest_create=milestone_contest_create ) @pytest.fixture def milestone_contest( product_user_wallet_yes: Product, milestone_contest_create: MilestoneContestCreate, ) -> Contest: from generalresearch.models.thl.contest.io import contest_create_to_contest return contest_create_to_contest( product_id=product_user_wallet_yes.uuid, contest_create=milestone_contest_create ) @pytest.fixture(scope="function") def milestone_contest_factory( product_user_wallet_yes: Product, milestone_contest_create: MilestoneContestCreate, contest_manager: ContestManager, ) -> Callable[..., Contest]: def _inner(**kwargs): milestone_contest_create.update(**kwargs) return contest_manager.create( product_id=product_user_wallet_yes.uuid, contest_create=milestone_contest_create, ) return _inner @pytest.fixture def leaderboard_contest_create( product_user_wallet_yes: Product, ) -> LeaderboardContestCreate: from generalresearch.models.thl.contest import ( ContestPrize, ) from generalresearch.models.thl.contest.definitions import ( ContestPrizeKind, ContestType, ) from generalresearch.models.thl.contest.leaderboard import ( LeaderboardContestCreate, ) # This is what we'll get from the fastapi endpoint return LeaderboardContestCreate( name="test", contest_type=ContestType.LEADERBOARD, prizes=[ ContestPrize( name="$15 Cash", estimated_cash_value=USDCent(15_00), cash_amount=USDCent(15_00), kind=ContestPrizeKind.CASH, leaderboard_rank=1, ), ContestPrize( name="$10 Cash", estimated_cash_value=USDCent(10_00), cash_amount=USDCent(10_00), kind=ContestPrizeKind.CASH, leaderboard_rank=2, ), ], leaderboard_key=f"leaderboard:{product_user_wallet_yes.uuid}:us:daily:2025-01-01:complete_count", ) @pytest.fixture def leaderboard_contest_in_db( product_user_wallet_yes: Product, leaderboard_contest_create: LeaderboardContestCreate, contest_manager: ContestManager, ) -> Contest: return contest_manager.create( product_id=product_user_wallet_yes.uuid, contest_create=leaderboard_contest_create, ) @pytest.fixture def leaderboard_contest( product_user_wallet_yes: Product, leaderboard_contest_create: LeaderboardContestCreate, ): from generalresearch.models.thl.contest.io import contest_create_to_contest return contest_create_to_contest( product_id=product_user_wallet_yes.uuid, contest_create=leaderboard_contest_create, ) @pytest.fixture(scope="function") def leaderboard_contest_factory( product_user_wallet_yes: Product, leaderboard_contest_create: LeaderboardContestCreate, contest_manager: ContestManager, ) -> Callable[..., Contest]: def _inner(**kwargs): leaderboard_contest_create.update(**kwargs) return contest_manager.create( product_id=product_user_wallet_yes.uuid, contest_create=leaderboard_contest_create, ) return _inner @pytest.fixture def user_with_money( request: Request, user_factory: Callable[..., User], product_user_wallet_yes: Product, thl_lm: ThlLedgerManager, ) -> User: params = getattr(request, "param", {}) or {} min_balance = int(params.get("min_balance", USDCent(1_00))) user: User = user_factory(product=product_user_wallet_yes) wallet = thl_lm.get_account_or_create_user_wallet(user) balance = thl_lm.get_account_balance(wallet) todo = min_balance - balance if todo > 0: # # Put money in user's wallet thl_lm.create_tx_user_bonus( user=user, ref_uuid=uuid4().hex, description="bonus", amount=Decimal(todo) / 100, ) print(f"wallet balance: {thl_lm.get_user_wallet_balance(user=user)}") return user