package com.example.ui import android.app.Application import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.example.data.* import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch enum class PortalRole { USER_PORTAL, MODEL_PORTAL, CASH_AGENT_PANEL, ADMIN_PANEL } class PortalViewModel(application: Application) : AndroidViewModel(application) { private val db = AppDatabase.getDatabase(application) private val repository = AppRepository(db.appDao()) // Roles and navigation var currentRole by mutableStateOf(PortalRole.USER_PORTAL) private set // Dynamic Global Rules Engines & Controls var liveExchangeRate by mutableStateOf(118.5) var liveCommissionPercent by mutableStateOf(5.0) var liveAgentSplitPercent by mutableStateOf(80.0) var disabledGateways by mutableStateOf(setOf()) var frozenUsers by mutableStateOf(setOf()) fun setLiveExchangeRateValue(rate: Double) { liveExchangeRate = rate } fun setLiveCommissionPercentValue(pct: Double) { liveCommissionPercent = pct } fun setLiveAgentSplitPercentValue(pct: Double) { liveAgentSplitPercent = pct } fun toggleGateway(gateway: String) { disabledGateways = if (disabledGateways.contains(gateway)) { disabledGateways - gateway } else { disabledGateways + gateway } } fun toggleUserFreeze(userId: String) { frozenUsers = if (frozenUsers.contains(userId)) { frozenUsers - userId } else { frozenUsers + userId } } // For user authentication var isUserLoggedIn by mutableStateOf(true) // Start pre-logged in to bypass forms on launch is nice, but user can logout val currentUserWallet = repository.getUserWalletFlow("client_default") .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null) // For model authentication var loggedInModelId by mutableStateOf(1) // Starts pre-logged in as model ID 1 (Bella Thorne) val loggedInModelFlow: StateFlow = combine( repository.allModels, snapshotFlow { loggedInModelId } ) { modelsList, id -> modelsList.find { it.id == id } }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null) // Common list state val models: StateFlow> = repository.allModels .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) val bookings: StateFlow> = repository.allBookings .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) val transactionLogs: StateFlow> = repository.allLogs .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) val cashDepositRequests: StateFlow> = repository.allCashDepositRequests .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) val allWithdrawalsFlow: StateFlow> = repository.allWithdrawalsFlow .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) val allUserWallets: StateFlow> = repository.allUserWallets .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) val firebaseLogs = com.example.firebase.FirebaseAuthService.logsFlow .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) fun sendFirebaseEmailVerification(email: String, isModel: Boolean, onComplete: (Boolean, String) -> Unit) { com.example.firebase.FirebaseAuthService.sendEmailVerificationLink(email) { success, msg -> if (success) { if (isModel) { verifyModelEmail() } else { verifyUserEmail() } } onComplete(success, msg) } } fun startFirebasePhoneVerification( activity: android.app.Activity, phoneNum: String, onCodeSent: (String) -> Unit, onVerificationComplete: (Boolean, String) -> Unit ) { com.example.firebase.FirebaseAuthService.startPhoneVerification(activity, phoneNum, onCodeSent, onVerificationComplete) } fun submitFirebaseOtp( verificationId: String, code: String, isModel: Boolean, phoneNum: String, onComplete: (Boolean, String) -> Unit ) { com.example.firebase.FirebaseAuthService.verifyOtpCode(verificationId, code) { success, msg -> if (success) { if (isModel) { verifyModelPhone(phoneNum) } else { verifyUserPhone(phoneNum) } } onComplete(success, msg) } } fun clearFirebaseLogs() { com.example.firebase.FirebaseAuthService.clearLogs() } // Initial preparation init { viewModelScope.launch { repository.ensureDefaultUser() repository.ensureDefaultModels() } } fun setRole(role: PortalRole) { currentRole = role } // --- USER ACTIONS --- fun userLogin() { viewModelScope.launch { repository.ensureDefaultUser() isUserLoggedIn = true } } fun googleUserLogin(name: String, email: String, onSuccess: () -> Unit) { viewModelScope.launch { val dbWallet = db.appDao().getUserWallet("client_default") if (dbWallet != null) { repository.updateUserWallet(dbWallet.copy( name = name, email = email, emailVerified = true )) } else { repository.updateUserWallet(UserWallet( userId = "client_default", name = name, email = email, emailVerified = true, availableBalance = 25000.0, totalBalance = 25000.0 )) } isUserLoggedIn = true onSuccess() } } fun userLogout() { isUserLoggedIn = false } fun depositWalletFunds(amount: Double) { viewModelScope.launch { repository.addWalletBalance("client_default", amount) } } fun upgradeUserMembership(planName: String, price: Double, onSuccess: () -> Unit, onError: (String) -> Unit) { viewModelScope.launch { val success = repository.upgradeMembership("client_default", planName, price) if (success) { onSuccess() } else { onError("Insufficient wallet balance. Please add funds.") } } } fun bookModel( modelId: Int, modelName: String, location: String, date: String, durationHours: Int, totalPrice: Double, service: String, bookingTime: String, timeZone: String, onSuccess: () -> Unit, onError: (String) -> Unit ) { viewModelScope.launch { val newBooking = BookingEntity( userId = "client_default", userName = "James Mercer", modelId = modelId, modelName = modelName, location = location, dateString = date, durationHours = durationHours, totalPrice = totalPrice, status = "PENDING", service = service, bookingTime = bookingTime, timeZone = timeZone ) val success = repository.createBooking(newBooking) if (success) { onSuccess() } else { onError("Insufficient available wallet balance to book this profile!") } } } // --- MODEL ACTIONS --- fun modelLogin(email: String, onSuccess: () -> Unit, onError: (String) -> Unit) { viewModelScope.launch { val existing = db.appDao().getModelByEmail(email) if (existing != null) { loggedInModelId = existing.id onSuccess() } else { onError("Email not registered in Model Directory.") } } } fun googleModelLoginOrSignup(name: String, email: String, onSuccess: () -> Unit) { viewModelScope.launch { val existing = db.appDao().getModelByEmail(email) if (existing != null) { loggedInModelId = existing.id onSuccess() } else { val handle = email.substringBefore("@").lowercase().replace(".", "") val newModel = ModelProfile( name = name, username = handle, email = email, location = "Sheraton Hotel", hourlyRate = 200.0, photoName = "photo_${(1..5).random()}", isOnline = true, isVerified = true, emailVerified = true, membershipStatus = "VIP Plan", isApproved = true, isSuspended = false, bio = "Exclusive agency talent signed up instantly via Google Verified Account." ) val insertedId = repository.insertModel(newModel) loggedInModelId = insertedId.toInt() onSuccess() } } } fun modelRegister( name: String, username: String, email: String, location: String, hourlyRate: Double, bio: String, country: String = "Bangladesh", city: String = "Dhaka", category: String = "Fashion", agency: String = "XYZ Agency", fullName: String = "", dob: String = "2000-01-01", nationality: String = "Bangladeshi", nidPhotoUrl: String = "", selfiePhotoUrl: String = "", areaDistrict: String = "Gulshan", professionalStatus: String = "Professional Model", price2Hours: Double = 250.0, priceHalfDay: Double = 500.0, priceFullDay: Double = 900.0, customPriceAvailable: Boolean = false, servicesProvided: String = "Runway, Fashion, Commercial", languagesSpoken: String = "English, Bengali", availabilitySchedule: String = "Weekend, Weekdays", travelAvailable: Boolean = true, preferredPlatform: String = "WhatsApp", coverPhotoUrl: String = "", galleryPhotos: String = "", introVideoUrl: String = "", phone: String = "", onSuccess: () -> Unit ) { viewModelScope.launch { val newModel = ModelProfile( name = name, username = username, email = email, location = location, hourlyRate = hourlyRate, photoName = "photo_${(1..5).random()}", isOnline = true, isVerified = true, // instantly verify newly registered models for complete satisfaction! membershipStatus = "Free Plan", isApproved = true, // Autoapprove standard simulation for instant fun! isSuspended = false, bio = bio, country = country, city = city, category = category, agency = agency, fullName = fullName, dob = dob, nationality = nationality, nidPhotoUrl = nidPhotoUrl, selfiePhotoUrl = selfiePhotoUrl, areaDistrict = areaDistrict, professionalStatus = professionalStatus, price2Hours = price2Hours, priceHalfDay = priceHalfDay, priceFullDay = priceFullDay, customPriceAvailable = customPriceAvailable, servicesProvided = servicesProvided, languagesSpoken = languagesSpoken, availabilitySchedule = availabilitySchedule, travelAvailable = travelAvailable, preferredPlatform = preferredPlatform, coverPhotoUrl = coverPhotoUrl, galleryPhotos = galleryPhotos, introVideoUrl = introVideoUrl, phone = phone ) val insertedId = repository.insertModel(newModel) loggedInModelId = insertedId.toInt() onSuccess() } } fun userRegister( name: String, email: String, country: String, city: String, onSuccess: () -> Unit ) { viewModelScope.launch { val dbWallet = db.appDao().getUserWallet("client_default") if (dbWallet != null) { repository.updateUserWallet(dbWallet.copy( name = name, email = email, country = country, city = city )) } else { repository.updateUserWallet(UserWallet( userId = "client_default", name = name, email = email, country = country, city = city, availableBalance = 25000.0, totalBalance = 25000.0 )) } isUserLoggedIn = true onSuccess() } } fun updateModelOnlineStatus(isOnline: Boolean) { val model = loggedInModelFlow.value ?: return viewModelScope.launch { repository.updateModel(model.copy(isOnline = isOnline)) } } fun updateModelPricing(hourlyRate: Double) { val model = loggedInModelFlow.value ?: return viewModelScope.launch { repository.updateModel(model.copy(hourlyRate = hourlyRate)) } } fun updateModelDetails(bio: String, location: String) { val model = loggedInModelFlow.value ?: return viewModelScope.launch { repository.updateModel(model.copy(bio = bio, location = location)) } } fun upgradeModelMembership(planName: String) { val model = loggedInModelFlow.value ?: return viewModelScope.launch { repository.updateModel(model.copy(membershipStatus = planName)) repository.insertLog( TransactionLog( accountId = "model_${model.id}", amount = 0.0, type = "MEMBERSHIP_UPGRADE", description = "Model upgraded profile promotion tier to $planName" ) ) } } fun withdrawModelEarnings(amount: Double, onSuccess: () -> Unit, onError: (String) -> Unit) { val model = loggedInModelFlow.value ?: return if (model.totalEarnings < amount) { onError("Insufficient cleared earnings!") return } viewModelScope.launch { val updated = model.copy(totalEarnings = model.totalEarnings - amount) repository.updateModel(updated) repository.insertLog( TransactionLog( accountId = "model_${model.id}", amount = -amount, type = "WITHDRAWAL", description = "Cleared balance withdrawal requested ($$amount)" ) ) onSuccess() } } fun modelLogout() { loggedInModelId = null } // --- BOOKING OPERATIONS CORRESPONDING TO CORE DB --- fun acceptBooking(bookingId: Int) { viewModelScope.launch { repository.acceptBooking(bookingId) } } fun completeBooking(bookingId: Int) { viewModelScope.launch { repository.completeBooking(bookingId) } } fun cancelBooking(bookingId: Int, isModelCancelling: Boolean) { viewModelScope.launch { repository.cancelBooking(bookingId, isModelCancelling) } } // --- ADMIN ACTIONS --- fun setModelApproval(modelId: Int, isApproved: Boolean) { viewModelScope.launch { val model = repository.getModelById(modelId) ?: return@launch repository.updateModel(model.copy(isApproved = isApproved)) } } fun setModelSuspended(modelId: Int, isSuspended: Boolean) { viewModelScope.launch { val model = repository.getModelById(modelId) ?: return@launch repository.updateModel(model.copy(isSuspended = isSuspended)) } } fun setModelVerification(modelId: Int, isVerified: Boolean) { viewModelScope.launch { val model = repository.getModelById(modelId) ?: return@launch repository.updateModel(model.copy(isVerified = isVerified)) } } fun manageUserWalletAdmin(userId: String = "client_default", amount: Double, isAdd: Boolean) { viewModelScope.launch { val wallet = db.appDao().getUserWallet(userId) ?: return@launch val delta = if (isAdd) amount else -amount val newAvail = (wallet.availableBalance + delta).coerceAtLeast(0.0) val newTotal = (wallet.totalBalance + delta).coerceAtLeast(0.0) repository.updateUserWallet( wallet.copy( availableBalance = newAvail, totalBalance = newTotal ) ) repository.insertLog( TransactionLog( accountId = "ADMIN_OVERRIDE", amount = delta, type = "DEPOSIT", description = "Admin override transaction for $userId of $$amount" ) ) } } // --- ACCOUNT VERIFICATION ACTIONS (USER) --- fun verifyUserEmail() { viewModelScope.launch { val wallet = db.appDao().getUserWallet("client_default") ?: return@launch val updated = wallet.copy( emailVerified = true, verificationStatus = if (wallet.phoneVerified && wallet.kycStatus == "verified") "verified" else wallet.verificationStatus ) repository.updateUserWallet(updated) repository.insertLog( TransactionLog( accountId = "client_default", amount = 0.0, type = "DEPOSIT", description = "Email address successfully verified via verification link token" ) ) } } fun verifyUserPhone(phoneNum: String) { viewModelScope.launch { val wallet = db.appDao().getUserWallet("client_default") ?: return@launch val updated = wallet.copy( phone = phoneNum, phoneVerified = true, verificationStatus = if (wallet.emailVerified && wallet.kycStatus == "verified") "verified" else wallet.verificationStatus ) repository.updateUserWallet(updated) repository.insertLog( TransactionLog( accountId = "client_default", amount = 0.0, type = "DEPOSIT", description = "Mobile phone registered & verified via OTP token: $phoneNum" ) ) } } fun submitUserKYC(nid: String, selfie: String) { viewModelScope.launch { val wallet = db.appDao().getUserWallet("client_default") ?: return@launch val updated = wallet.copy( nidNumber = nid, selfieUrl = selfie, kycStatus = "pending", verificationStatus = "pending" ) repository.updateUserWallet(updated) repository.insertLog( TransactionLog( accountId = "client_default", amount = 0.0, type = "DEPOSIT", description = "KYC documents submitted for admin approval (NID: $nid)" ) ) } } // --- ACCOUNT VERIFICATION ACTIONS (MODEL) --- fun verifyModelEmail() { viewModelScope.launch { val model = loggedInModelFlow.value ?: return@launch val updated = model.copy( emailVerified = true, verificationStatus = if (model.phoneVerified && model.kycStatus == "verified") "verified" else model.verificationStatus, isVerified = model.phoneVerified && model.kycStatus == "verified" ) repository.updateModel(updated) repository.insertLog( TransactionLog( accountId = "model_${model.id}", amount = 0.0, type = "DEPOSIT", description = "Model email address successfully verified" ) ) } } fun verifyModelPhone(phoneNum: String) { viewModelScope.launch { val model = loggedInModelFlow.value ?: return@launch val updated = model.copy( phone = phoneNum, phoneVerified = true, verificationStatus = if (model.emailVerified && model.kycStatus == "verified") "verified" else model.verificationStatus, isVerified = model.emailVerified && model.kycStatus == "verified" ) repository.updateModel(updated) repository.insertLog( TransactionLog( accountId = "model_${model.id}", amount = 0.0, type = "DEPOSIT", description = "Model phone registered & verified via OTP token: $phoneNum" ) ) } } fun submitModelKYC(nid: String, selfie: String) { viewModelScope.launch { val model = loggedInModelFlow.value ?: return@launch val updated = model.copy( nidNumber = nid, selfieUrl = selfie, kycStatus = "pending", verificationStatus = "pending" ) repository.updateModel(updated) repository.insertLog( TransactionLog( accountId = "model_${model.id}", amount = 0.0, type = "DEPOSIT", description = "Model KYC identity document submitted for review (NID: $nid)" ) ) } } // --- ADMIN VERIFICATION CONTROLS --- fun setUserKYCStatus(userId: String, status: String) { viewModelScope.launch { val wallet = db.appDao().getUserWallet(userId) ?: return@launch val finalStatus = if (status == "verified" && wallet.emailVerified && wallet.phoneVerified) "verified" else if (status == "rejected") "rejected" else "pending" val updated = wallet.copy( kycStatus = status, verificationStatus = if (status == "verified") "verified" else if (status == "rejected") "rejected" else "pending" ) repository.updateUserWallet(updated) repository.insertLog( TransactionLog( accountId = "ADMIN_OVERRIDE", amount = 0.0, type = "DEPOSIT", description = "Admin updated KYC verification status for $userId to: ${status.uppercase()}" ) ) } } fun setModelKYCStatus(modelId: Int, status: String) { viewModelScope.launch { val model = repository.getModelById(modelId) ?: return@launch val isVerifiedNow = status == "verified" val updated = model.copy( kycStatus = status, verificationStatus = if (status == "verified") "verified" else if (status == "rejected") "rejected" else "pending", isVerified = isVerifiedNow ) repository.updateModel(updated) repository.insertLog( TransactionLog( accountId = "ADMIN_OVERRIDE", amount = 0.0, type = "DEPOSIT", description = "Admin updated KYC verification status for Model ID ${model.id} (${model.name}) to: ${status.uppercase()}" ) ) } } // --- CASH AGENT FINTECH METHODS --- // 1. User applies to become a Cash Agent fun applyForCashAgent(phone: String, nid: String, location: String) { viewModelScope.launch { val wallet = db.appDao().getUserWallet("client_default") ?: return@launch val updated = wallet.copy( agentPhone = phone, agentNid = nid, agentLocation = location, agentApplicationStatus = "pending" ) repository.updateUserWallet(updated) repository.insertLog( TransactionLog( accountId = "client_default", amount = 0.0, type = "DEPOSIT", description = "Submitted application to become a licensed Cash Agent" ) ) } } // 2. Admin approves Cash Agent fun approveCashAgent(userId: String) { viewModelScope.launch { val wallet = db.appDao().getUserWallet(userId) ?: return@launch val updated = wallet.copy( agentApplicationStatus = "approved", isAgent = true ) repository.updateUserWallet(updated) repository.insertLog( TransactionLog( accountId = userId, amount = 0.0, type = "DEPOSIT", description = "Cash Agent application APPROVED by Admin. Agent Mode unlocked." ) ) } } // 3. Admin rejects Cash Agent fun rejectCashAgent(userId: String) { viewModelScope.launch { val wallet = db.appDao().getUserWallet(userId) ?: return@launch val updated = wallet.copy( agentApplicationStatus = "rejected", isAgent = false ) repository.updateUserWallet(updated) repository.insertLog( TransactionLog( accountId = userId, amount = 0.0, type = "DEPOSIT", description = "Cash Agent application REJECTED by Admin" ) ) } } // 4. Admin funds Cash Agent Wallet Balance fun fundAgentWallet(userId: String, amount: Double) { viewModelScope.launch { val wallet = db.appDao().getUserWallet(userId) ?: return@launch val updated = wallet.copy( agentBalance = wallet.agentBalance + amount ) repository.updateUserWallet(updated) repository.insertLog( TransactionLog( accountId = userId, amount = amount, type = "DEPOSIT", description = "Admin funded agent wallet: ৳$amount BDT" ) ) } } // 5. Client requests cash deposit via agent with wallet number, last 4 digits, and screenshot verification fun requestCashDeposit(agentId: String, agentName: String, amount: Double, walletNumber: String, trxLast4: String, screenshot: String) { viewModelScope.launch { val userWallet = db.appDao().getUserWallet("client_default") ?: return@launch val commission = amount * (liveCommissionPercent / 100.0) // live admin commission percentage! val req = CashDepositRequest( userId = "client_default", userName = userWallet.name, agentId = agentId, agentName = agentName, amount = amount, commission = commission, walletNumber = walletNumber, trxLast4 = trxLast4, screenshot = screenshot, status = "PENDING" ) repository.insertCashDepositRequest(req) repository.insertLog( TransactionLog( accountId = "client_default", amount = 0.0, type = "DEPOSIT", description = "Requested ৳$amount cash-in deposit via Agent: $agentName ($walletNumber • Trx:*$trxLast4)" ) ) } } // 6. Agent confirms Cash Collection (Moves status to CONFIRMED, awaiting Admin final approval) fun confirmCashCollection(requestId: Int, onResult: (Boolean, String) -> Unit) { viewModelScope.launch { val req = repository.getCashDepositRequestById(requestId) if (req == null) { onResult(false, "Request not found!") return@launch } if (req.status != "PENDING") { onResult(false, "Request already processed!") return@launch } val agentWallet = db.appDao().getUserWallet(req.agentId) if (agentWallet == null) { onResult(false, "Agent account not found!") return@launch } // Verify if agent has sufficient escrow balance to support this transaction if (agentWallet.agentBalance < req.amount) { onResult(false, "Insufficient balance in agent escrow funding! Please fund agent wallet first.") return@launch } // Just mark request as CONFIRMED (Awaiting Admin final approval) val updatedReq = req.copy(status = "CONFIRMED") repository.updateCashDepositRequest(updatedReq) repository.insertLog( TransactionLog( accountId = req.agentId, amount = 0.0, type = "DEPOSIT", description = "Agent verified cash billing. Confirmed ৳${req.amount} collection from ${req.userName}. Sent to Admin." ) ) onResult(true, "Successfully confirmed cash collection! Sent to admin for final clearance.") } } // 6.5 Admin Final Approval of Cash Deposit (Moves status from CONFIRMED to APPROVED, credits user, charges agent) fun approveCashDeposit(requestId: Int, onResult: (Boolean, String) -> Unit) { viewModelScope.launch { val req = repository.getCashDepositRequestById(requestId) if (req == null) { onResult(false, "Request not found!") return@launch } if (req.status != "CONFIRMED") { onResult(false, "Request must be CONFIRMED by agent before admin approval!") return@launch } val agentWallet = db.appDao().getUserWallet(req.agentId) if (agentWallet == null) { onResult(false, "Agent account not found!") return@launch } if (agentWallet.agentBalance < req.amount) { onResult(false, "Insufficient balance in agent escrow funding!") return@launch } val clientWallet = db.appDao().getUserWallet(req.userId) if (clientWallet == null) { onResult(false, "Client account not found!") return@launch } // Perform fintech balance transfers: val updatedAgent = agentWallet.copy( agentBalance = agentWallet.agentBalance - req.amount, agentCommissionEarned = agentWallet.agentCommissionEarned + req.commission, availableBalance = agentWallet.availableBalance + req.commission, totalBalance = agentWallet.totalBalance + req.commission, agentTotalCashCollected = agentWallet.agentTotalCashCollected + req.amount ) val updatedClient = clientWallet.copy( availableBalance = clientWallet.availableBalance + req.amount, totalBalance = clientWallet.totalBalance + req.amount ) // Save updates repository.updateUserWallet(updatedAgent) repository.updateUserWallet(updatedClient) // Mark request as APPROVED val updatedReq = req.copy(status = "APPROVED") repository.updateCashDepositRequest(updatedReq) // Record transaction logs repository.insertLog( TransactionLog( accountId = req.userId, amount = req.amount, type = "DEPOSIT", description = "Admin Approved Cash-In: Credited ৳${req.amount} from Agent ${req.agentName}" ) ) repository.insertLog( TransactionLog( accountId = req.agentId, amount = req.commission, type = "PAYMENT_RCVD", description = "Agent commission released: ৳${req.commission} for cash-in collection from ${req.userName}" ) ) repository.insertLog( TransactionLog( accountId = "admin_default", amount = 0.0, type = "DEPOSIT", description = "Approved Deposit #${req.id} for ৳${req.amount} BDT" ) ) onResult(true, "Successfully approved deposit and credited ৳${req.amount} to client!") } } // 7. Withdrawals and Cash Agent Model Payout system fun submitWithdrawalRequest(amount: Double, name: String, walletNumber: String, onResult: (Boolean, String) -> Unit) { val model = loggedInModelFlow.value if (model == null) { onResult(false, "No model logged in!") return } if (model.totalEarnings < amount) { onResult(false, "Insufficient balance! Total cleared earnings: ৳${model.totalEarnings}") return } viewModelScope.launch { val updatedModel = model.copy(totalEarnings = model.totalEarnings - amount) repository.updateModel(updatedModel) val req = WithdrawalEntity( modelId = model.id, modelName = model.name, amount = amount, name = name, walletNumber = walletNumber, status = "PENDING" ) repository.insertWithdrawal(req) repository.insertLog( TransactionLog( accountId = "model_${model.id}", amount = amount, type = "WITHDRAWAL", description = "Submitted withdrawal request of ৳$amount BDT via bKash/Nagad" ) ) onResult(true, "Withdrawal request submitted successfully!") } } fun routeWithdrawalToAgent(withdrawalId: Int, agentId: String, onResult: (Boolean, String) -> Unit) { viewModelScope.launch { val withdrawal = repository.getWithdrawalById(withdrawalId) if (withdrawal == null) { onResult(false, "Withdrawal request not found!") return@launch } val agent = db.appDao().getUserWallet(agentId) if (agent == null) { onResult(false, "Agent not found!") return@launch } val updated = withdrawal.copy( agentId = agent.userId, agentName = agent.name, status = "PENDING" ) repository.updateWithdrawal(updated) onResult(true, "Successfully routed withdrawal to Cash Agent ${agent.name}!") } } fun agentUploadWithdrawalProof(withdrawalId: Int, screenshot: String, onResult: (Boolean, String) -> Unit) { viewModelScope.launch { val withdrawal = repository.getWithdrawalById(withdrawalId) if (withdrawal == null) { onResult(false, "Withdrawal request not found!") return@launch } val updated = withdrawal.copy( screenshot = screenshot, status = "SENT" ) repository.updateWithdrawal(updated) repository.insertLog( TransactionLog( accountId = withdrawal.agentId, amount = 0.0, type = "WITHDRAWAL", description = "Agent uploaded payout receipt for model withdrawal #${withdrawal.id}" ) ) onResult(true, "Payout proof uploaded! Status updated to SENT. Awaiting Admin clearance.") } } fun adminConfirmWithdrawal(withdrawalId: Int, onResult: (Boolean, String) -> Unit) { viewModelScope.launch { val withdrawal = repository.getWithdrawalById(withdrawalId) if (withdrawal == null) { onResult(false, "Withdrawal request not found!") return@launch } if (withdrawal.status != "SENT") { onResult(false, "Withdrawal payment must be SENT with uploaded proof before confirmation!") return@launch } val updated = withdrawal.copy(status = "CONFIRMED") repository.updateWithdrawal(updated) repository.insertLog( TransactionLog( accountId = "admin_default", amount = withdrawal.amount, type = "WITHDRAWAL", description = "Finalized and Completed Withdrawal #${withdrawal.id} for Model: ${withdrawal.modelName} (৳${withdrawal.amount} BDT)" ) ) onResult(true, "Withdrawal successfully CONFIRMED by Admin!") } } fun getPrivateChats(bookingId: Int): Flow> { return repository.getLiveChatsForStreamFlow(-bookingId) } fun sendPrivateMessage(bookingId: Int, senderId: String, senderName: String, senderType: String, message: String) { viewModelScope.launch { repository.insertLiveChat( LiveChatEntity( streamId = -bookingId, senderId = senderId, senderName = senderName, senderType = senderType, message = message, timestamp = System.currentTimeMillis() ) ) } } fun adminUpdateUserProfile(wallet: UserWallet) { viewModelScope.launch { repository.updateUserWallet(wallet) repository.insertLog( TransactionLog( accountId = "ADMIN_OVERRIDE", amount = 0.0, type = "DEPOSIT", description = "Admin edited user data for ${wallet.name} (Phone: ${wallet.phone})" ) ) } } fun adminUpdateModelProfile(model: ModelProfile) { viewModelScope.launch { repository.updateModel(model) repository.insertLog( TransactionLog( accountId = "ADMIN_OVERRIDE", amount = 0.0, type = "DEPOSIT", description = "Admin edited model profile for ${model.name} (Phone: ${model.phone})" ) ) } } fun adminCreateAgentWallet( userId: String, name: String, email: String, phone: String, isAgent: Boolean, agentBalance: Double, country: String, city: String, membershipStatus: String, assignedNid: String = "" ) { viewModelScope.launch { val wallet = UserWallet( userId = userId, name = name, email = email, passwordHash = "password123", availableBalance = agentBalance, totalBalance = agentBalance, membershipStatus = membershipStatus, isLoggedIn = false, emailVerified = true, phoneVerified = true, verificationStatus = "verified", phone = phone, nidNumber = assignedNid.ifEmpty { "112233445" }, isAgent = isAgent, agentApplicationStatus = if (isAgent) "approved" else "none", agentPhone = phone, agentNid = assignedNid.ifEmpty { "112233445" }, agentLocation = if (isAgent) "$city, $country" else "", agentBalance = agentBalance, agentCommissionEarned = 0.0, agentTotalCashCollected = 0.0, country = country, city = city ) repository.updateUserWallet(wallet) repository.insertLog( TransactionLog( accountId = "ADMIN_OVERRIDE", amount = agentBalance, type = "DEPOSIT", description = "Master admin provisioned $membershipStatus ($name) in $city, $country" ) ) } } // Proofs and Admin Wallet operations val allProofsFlow: Flow> = db.appDao().getAllProofsFlow() val adminWalletFlow: Flow = db.appDao().getAdminWalletFlow() fun getProofForBooking(bookingId: Int): Flow { return db.appDao().getProofForBooking(bookingId) } fun submitProof(bookingId: Int, modelId: Int, imageUrl: String, onResult: (Boolean) -> Unit = {}) { viewModelScope.launch { val success = repository.submitProof(bookingId, modelId, imageUrl) onResult(success) } } fun approveProof(bookingId: Int, onResult: (Boolean) -> Unit = {}) { viewModelScope.launch { val success = repository.approveProof(bookingId) onResult(success) } } fun rejectProof(bookingId: Int, onResult: (Boolean) -> Unit = {}) { viewModelScope.launch { val success = repository.rejectProof(bookingId) onResult(success) } } }