import { collection, collectionGroup, query, where, orderBy, QueryConstraint, limit, startAfter, doc, getDocs, getDoc, DocumentSnapshot, Query, } from 'firebase/firestore' import { uniq } from 'lodash' import { db } from './init' import { Bet, LimitBet } from 'common/bet' import { Contract } from 'common/contract' import { getValues, listenForValues } from './utils' import { getContractFromId } from './contracts' import { filterDefined } from 'common/util/array' export type { Bet } function getBetsCollection(contractId: string) { return collection(db, 'contracts', contractId, 'bets') } export async function listAllBets(contractId: string) { return await getValues( query(getBetsCollection(contractId), orderBy('createdTime', 'desc')) ) } const DAY_IN_MS = 24 * 60 * 60 * 1000 // Define "recent" as "<24 hours ago" for now const recentBetsQuery = query( collectionGroup(db, 'bets'), where('createdTime', '>', Date.now() - DAY_IN_MS), orderBy('createdTime', 'desc') ) export async function getRecentBets() { return getValues(recentBetsQuery) } export function listenForRecentBets(setBets: (bets: Bet[]) => void) { return listenForValues(recentBetsQuery, setBets) } export async function getRecentContractBets(contractId: string) { const q = query( getBetsCollection(contractId), where('createdTime', '>', Date.now() - DAY_IN_MS), orderBy('createdTime', 'desc') ) return getValues(q) } export function listenForBets( contractId: string, setBets: (bets: Bet[]) => void ) { return listenForValues( query(getBetsCollection(contractId), orderBy('createdTime', 'desc')), setBets ) } export async function getUserBets(userId: string) { return getValues(getUserBetsQuery(userId)) } export function getUserBetsQuery(userId: string) { return query( collectionGroup(db, 'bets'), where('userId', '==', userId), orderBy('createdTime', 'desc') ) as Query } export async function getBets(options: { userId?: string contractId?: string before?: string limit: number }) { const { userId, contractId, before } = options const queryParts: QueryConstraint[] = [ orderBy('createdTime', 'desc'), limit(options.limit), ] if (userId) { queryParts.push(where('userId', '==', userId)) } if (before) { let beforeSnap: DocumentSnapshot if (contractId) { beforeSnap = await getDoc( doc(db, 'contracts', contractId, 'bets', before) ) } else { beforeSnap = ( await getDocs( query(collectionGroup(db, 'bets'), where('id', '==', before)) ) ).docs[0] } queryParts.push(startAfter(beforeSnap)) } const querySource = contractId ? collection(db, 'contracts', contractId, 'bets') : collectionGroup(db, 'bets') return await getValues(query(querySource, ...queryParts)) } export async function getContractsOfUserBets(userId: string) { const bets = await getUserBets(userId) const contractIds = uniq( bets.filter((b) => !b.isAnte).map((bet) => bet.contractId) ) const contracts = await Promise.all( contractIds.map((contractId) => getContractFromId(contractId)) ) return filterDefined(contracts) } export function listenForUserContractBets( userId: string, contractId: string, setBets: (bets: Bet[]) => void ) { const betsQuery = query( collection(db, 'contracts', contractId, 'bets'), where('userId', '==', userId), orderBy('createdTime', 'desc') ) return listenForValues(betsQuery, setBets) } export function listenForUnfilledBets( contractId: string, setBets: (bets: LimitBet[]) => void ) { const betsQuery = query( collection(db, 'contracts', contractId, 'bets'), where('isFilled', '==', false), where('isCancelled', '==', false), orderBy('createdTime', 'desc') ) return listenForValues(betsQuery, setBets) } export function withoutAnteBets(contract: Contract, bets?: Bet[]) { const { createdTime } = contract if ( bets && bets.length >= 2 && bets[0].createdTime === createdTime && bets[1].createdTime === createdTime ) { return bets.slice(2) } return bets?.filter((bet) => !bet.isAnte) ?? [] }