package com.example.data import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.firstOrNull class AppRepository(private val appDao: AppDao) { val allModels: Flow> = appDao.getAllModelsFlow() val allBookings: Flow> = appDao.getAllBookingsFlow() val allLogs: Flow> = appDao.getAllLogsFlow() val allUserWallets: Flow> = appDao.getAllUserWallets() val allCashDepositRequests: Flow> = appDao.getAllCashDepositRequestsFlow() fun getUserWalletFlow(userId: String): Flow = appDao.getUserWalletFlow(userId) fun getModelFlow(id: Int): Flow = appDao.getModelFlow(id) fun getBookingsForUser(userId: String): Flow> = appDao.getBookingsForUserFlow(userId) fun getBookingsForModel(modelId: Int): Flow> = appDao.getBookingsForModelFlow(modelId) fun getLogsForAccount(accountId: String): Flow> = appDao.getLogsForAccountFlow(accountId) fun getCashDepositRequestsForAgent(agentId: String): Flow> = appDao.getCashDepositRequestsForAgentFlow(agentId) suspend fun getModelById(id: Int) = appDao.getModelById(id) suspend fun updateModel(model: ModelProfile) = appDao.updateModel(model) suspend fun deleteModel(model: ModelProfile) = appDao.deleteModel(model) suspend fun insertModel(model: ModelProfile) = appDao.insertModel(model) suspend fun updateBooking(booking: BookingEntity) = appDao.updateBooking(booking) suspend fun updateUserWallet(wallet: UserWallet) = appDao.insertUserWallet(wallet) suspend fun insertLog(log: TransactionLog) = appDao.insertLog(log) suspend fun getCashDepositRequestById(id: Int) = appDao.getCashDepositRequestById(id) suspend fun insertCashDepositRequest(request: CashDepositRequest) = appDao.insertCashDepositRequest(request) suspend fun updateCashDepositRequest(request: CashDepositRequest) = appDao.updateCashDepositRequest(request) // Withdrawal Repository operations val allWithdrawalsFlow: Flow> = appDao.getAllWithdrawalsFlow() suspend fun getWithdrawalById(id: Int) = appDao.getWithdrawalById(id) suspend fun insertWithdrawal(withdrawal: WithdrawalEntity) = appDao.insertWithdrawal(withdrawal) suspend fun updateWithdrawal(withdrawal: WithdrawalEntity) = appDao.updateWithdrawal(withdrawal) // Live Stream & Live Chat Repository methods val activeLiveStreams: Flow> = appDao.getActiveLiveStreamsFlow() val allLiveStreams: Flow> = appDao.getAllLiveStreamsFlow() fun getLiveChatsForStreamFlow(streamId: Int): Flow> = appDao.getLiveChatsForStreamFlow(streamId) suspend fun getLiveStreamById(id: Int) = appDao.getLiveStreamById(id) suspend fun getActiveLiveStreamByModel(modelId: Int) = appDao.getActiveLiveStreamByModel(modelId) suspend fun insertLiveStream(stream: LiveStreamEntity): Long = appDao.insertLiveStream(stream) suspend fun updateLiveStream(stream: LiveStreamEntity) = appDao.updateLiveStream(stream) suspend fun insertLiveChat(chat: LiveChatEntity): Long = appDao.insertLiveChat(chat) suspend fun ensureDefaultUser(userId: String = "client_default") { val existing = appDao.getUserWallet(userId) if (existing == null) { appDao.insertUserWallet( UserWallet( userId = userId, name = "James Mercer", email = "james@example.com", passwordHash = "password123", availableBalance = 25000.0, totalBalance = 25000.0, membershipStatus = "Free Membership", isLoggedIn = false ) ) } } suspend fun createBooking(booking: BookingEntity): Boolean { // Validate user balance before confirming booking val wallet = appDao.getUserWallet(booking.userId) ?: return false if (wallet.availableBalance < booking.totalPrice) { return false // insufficient balance } // Deduct available balance (freeze funds) val updatedWallet = wallet.copy( availableBalance = wallet.availableBalance - booking.totalPrice ) appDao.insertUserWallet(updatedWallet) // Insert booking appDao.insertBooking(booking) // Add Transaction Log appDao.insertLog( TransactionLog( accountId = booking.userId, amount = -booking.totalPrice, type = "PAYMENT_SENT", description = "Frozen payment for booking with ${booking.modelName} (Pending approval)" ) ) return true } suspend fun acceptBooking(bookingId: Int): Boolean { val booking = appDao.getBookingById(bookingId) ?: return false if (booking.status != "PENDING") return false val updatedBooking = booking.copy(status = "ACCEPTED") appDao.updateBooking(updatedBooking) // Optionally, credit pending earnings to model val model = appDao.getModelById(booking.modelId) ?: return true val updatedModel = model.copy( pendingEarnings = model.pendingEarnings + booking.totalPrice ) appDao.updateModel(updatedModel) return true } suspend fun completeBooking(bookingId: Int): Boolean { val booking = appDao.getBookingById(bookingId) ?: return false if (booking.status != "ACCEPTED" && booking.status != "PROOF_UPLOADED" && booking.status != "PENDING") return false val updatedBooking = booking.copy(status = "COMPLETED") appDao.updateBooking(updatedBooking) // Settle wallet balance val wallet = appDao.getUserWallet(booking.userId) ?: return false // If it was still PENDING or ACCEPTED, we deduct totalBalance now, else it was frozen in availableBalance, so we also deduct totalBalance now val updatedWallet = wallet.copy( totalBalance = (wallet.totalBalance - booking.totalPrice).coerceAtLeast(0.0) ) appDao.insertUserWallet(updatedWallet) // Give payment to model (80% net payout, 20% system admin fee) val adminFee = booking.totalPrice * 0.20 val netPayout = booking.totalPrice - adminFee // Update Admin Wallet val adminWallet = appDao.getAdminWallet() ?: AdminWalletEntity() val updatedAdminWallet = adminWallet.copy( balance = adminWallet.balance + adminFee, totalEarnings = adminWallet.totalEarnings + adminFee ) appDao.insertAdminWallet(updatedAdminWallet) // Update Model val model = appDao.getModelById(booking.modelId) ?: return true val newPending = if (booking.status == "ACCEPTED" || booking.status == "PROOF_UPLOADED") { (model.pendingEarnings - booking.totalPrice).coerceAtLeast(0.0) } else { model.pendingEarnings } val updatedModel = model.copy( totalEarnings = model.totalEarnings + netPayout, pendingEarnings = newPending ) appDao.updateModel(updatedModel) // Store transaction log for user appDao.insertLog( TransactionLog( accountId = booking.userId, amount = -booking.totalPrice, type = "PAYMENT_SENT", description = "Settled payment for booking with ${booking.modelName} (Completed)" ) ) // Store transaction log for model appDao.insertLog( TransactionLog( accountId = "model_${booking.modelId}", amount = netPayout, type = "PAYMENT_RCVD", description = "Earned payout for booking with ${booking.userName} (Net 80% release)" ) ) // Store transaction log for admin appDao.insertLog( TransactionLog( accountId = "admin_default", amount = adminFee, type = "PAYMENT_RCVD", description = "Administrative marketplace fee of 20% from Booking #${booking.id}" ) ) return true } suspend fun submitProof(bookingId: Int, modelId: Int, imageUrl: String): Boolean { val booking = appDao.getBookingById(bookingId) ?: return false if (booking.status != "ACCEPTED") return false // Check if pre-existing proof val existing = appDao.getProofByBookingId(bookingId) if (existing != null) { val updated = existing.copy(imageUrl = imageUrl, status = "PENDING", timestamp = System.currentTimeMillis()) appDao.updateProof(updated) } else { val nproof = ProofEntity( bookingId = bookingId, modelId = modelId, imageUrl = imageUrl, status = "PENDING" ) appDao.insertProof(nproof) } // Change booking status to PROOF_UPLOADED val updatedBooking = booking.copy(status = "PROOF_UPLOADED") appDao.updateBooking(updatedBooking) return true } suspend fun approveProof(bookingId: Int): Boolean { val proof = appDao.getProofByBookingId(bookingId) ?: return false val updatedProof = proof.copy(status = "APPROVED") appDao.updateProof(updatedProof) // Release/Complete booking return completeBooking(bookingId) } suspend fun rejectProof(bookingId: Int): Boolean { val proof = appDao.getProofByBookingId(bookingId) ?: return false val updatedProof = proof.copy(status = "REJECTED") appDao.updateProof(updatedProof) // Return booking to ACCEPTED so model can submit another proof val booking = appDao.getBookingById(bookingId) ?: return false val updatedBooking = booking.copy(status = "ACCEPTED") appDao.updateBooking(updatedBooking) return true } suspend fun cancelBooking(bookingId: Int, isModelCancelling: Boolean): Boolean { val booking = appDao.getBookingById(bookingId) ?: return false if (booking.status == "COMPLETED" || booking.status == "CANCELLED") return false val updatedBooking = booking.copy(status = "CANCELLED") appDao.updateBooking(updatedBooking) // Refund user val wallet = appDao.getUserWallet(booking.userId) ?: return false val refundAvailable = wallet.availableBalance + booking.totalPrice val updatedWallet = wallet.copy( availableBalance = refundAvailable ) appDao.insertUserWallet(updatedWallet) // Adjust model earnings if they were accepted val model = appDao.getModelById(booking.modelId) if (model != null && booking.status == "ACCEPTED") { val updatedModel = model.copy( pendingEarnings = (model.pendingEarnings - booking.totalPrice).coerceAtLeast(0.0) ) appDao.updateModel(updatedModel) } // Add Refund Log val cancelParty = if (isModelCancelling) "Model" else "User" appDao.insertLog( TransactionLog( accountId = booking.userId, amount = booking.totalPrice, type = "DEPOSIT", description = "Refunded payment for booking with ${booking.modelName} (Cancelled by $cancelParty)" ) ) return true } suspend fun addWalletBalance(userId: String, amount: Double): Boolean { val wallet = appDao.getUserWallet(userId) ?: return false val updatedWallet = wallet.copy( availableBalance = wallet.availableBalance + amount, totalBalance = wallet.totalBalance + amount ) appDao.insertUserWallet(updatedWallet) appDao.insertLog( TransactionLog( accountId = userId, amount = amount, type = "DEPOSIT", description = "Added standard balance via Payment Gateway" ) ) return true } suspend fun upgradeMembership(userId: String, planName: String, cost: Double): Boolean { val wallet = appDao.getUserWallet(userId) ?: return false if (wallet.availableBalance < cost) return false val updatedWallet = wallet.copy( availableBalance = wallet.availableBalance - cost, totalBalance = wallet.totalBalance - cost, membershipStatus = planName ) appDao.insertUserWallet(updatedWallet) appDao.insertLog( TransactionLog( accountId = userId, amount = -cost, type = "MEMBERSHIP_UPGRADE", description = "Upgraded to $planName Plan" ) ) return true } suspend fun ensureDefaultModels() { val dbModels = appDao.getAllModels() if (dbModels.isEmpty()) { val defaults = listOf( ModelProfile( name = "Bella Thorne", username = "bellathorne", email = "bella@example.com", location = "Hotel Ritz", hourlyRate = 250.0, photoName = "photo_1", isOnline = true, isVerified = true, membershipStatus = "Premium Plan", bio = "International fashion model, beauty brand representative, and dramatic film actress.", rating = 4.9, isApproved = true, isSuspended = false, emailVerified = true, phoneVerified = true, verificationStatus = "verified", phone = "+44 7911 123456", nidNumber = "987541258", selfieUrl = "https://example.com/selfie_bella.jpg", kycStatus = "verified", country = "Bangladesh", city = "Dhaka", category = "Fashion", agency = "XYZ Agency" ), ModelProfile( name = "Alexander Pierce", username = "alexanderp", email = "alex@example.com", location = "Luxury Lounge", hourlyRate = 180.0, photoName = "photo_2", isOnline = true, isVerified = true, membershipStatus = "VIP Plan", bio = "Runway specialist and cover page male model for major luxury styling labels.", rating = 4.7, isApproved = true, isSuspended = false, emailVerified = true, phoneVerified = true, verificationStatus = "verified", phone = "+1 555-0199", nidNumber = "123654789", selfieUrl = "https://example.com/selfie_alex.jpg", kycStatus = "verified", country = "USA", city = "New York", category = "Commercial", agency = "Elite Models" ), ModelProfile( name = "Chloe Bennett", username = "chloeb", email = "chloe@example.com", location = "Grand Arena", hourlyRate = 300.0, photoName = "photo_3", isOnline = false, isVerified = true, membershipStatus = "Premium Plan", bio = "Red carpet host, premium sports modeling, and commercial television presenter.", rating = 4.9, isApproved = true, isSuspended = false, emailVerified = true, phoneVerified = true, verificationStatus = "verified", phone = "+1 555-0144", nidNumber = "456321789", selfieUrl = "https://example.com/selfie_chloe.jpg", kycStatus = "verified", country = "Bangladesh", city = "Dhaka", category = "Runway", agency = "XYZ Agency" ), ModelProfile( name = "Marcus Aurelius", username = "marcus_model", email = "marcus@example.com", location = "Vapor Safehouse", hourlyRate = 220.0, photoName = "photo_4", isOnline = true, isVerified = false, membershipStatus = "Free Plan", bio = "Alternative fitness modeling, artistic styling, and vintage classic aesthetic modeling.", rating = 4.5, isApproved = true, isSuspended = false, emailVerified = false, phoneVerified = false, verificationStatus = "unverified", phone = "", nidNumber = "", selfieUrl = "", kycStatus = "unverified", country = "Canada", city = "Toronto", category = "Fitness", agency = "Premier Talent" ), ModelProfile( name = "Serena Williams", username = "serenaw", email = "serena@example.com", location = "Premium Hotel", hourlyRate = 400.0, photoName = "photo_5", isOnline = true, isVerified = true, membershipStatus = "Premium Plan", bio = "Atheletic high-performance apparel model, high-fashion advocate and fitness coach.", rating = 5.0, isApproved = false, // starts unapproved by Admin as a simulation candidate! isSuspended = false, emailVerified = true, phoneVerified = true, verificationStatus = "verified", phone = "+1 555-0188", nidNumber = "789456123", selfieUrl = "https://example.com/selfie_serena.jpg", kycStatus = "verified", country = "India", city = "Mumbai", category = "Glamour", agency = "XYZ Agency" ) ) for (m in defaults) { appDao.insertModel(m) } } } }