package com.example.ui.viewmodel import android.app.Application import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope import com.example.data.local.AppDatabase import com.example.data.model.* import com.example.data.repository.SatarkRepository import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch data class UiState( val currentScreen: Screen = Screen.SPLASH, val previousScreen: Screen? = null, val currentLanguage: AppLanguage = AppLanguage.BN, val userName: String = "Mohammad Shakib", val userPhone: String = "+880 1712-345678", val isNidVerified: Boolean = true, val isAdminMode: Boolean = false, // Collections val companies: List = emptyList(), val reports: List = emptyList(), val publicWarnings: List = emptyList(), val notifications: List = emptyList(), val unreadNotificationCount: Int = 0, // Detail & Selection val selectedCompany: Company? = null, val selectedWarningId: String? = null, // Search filters val searchQuery: String = "", val selectedCategoryFilter: String? = null, val selectedDivisionFilter: String? = null, val selectedRiskFilter: VerificationStatus? = null, // Tracking val searchTrackingId: String = "BD-SCAM-8942", // Report submission flow val reportStep: Int = 1, // 1: Form, 2: Proof upload, 3: Success confirmation val reportTargetName: String = "", val reportContactInfo: String = "", val reportCategory: String = "Fake E-commerce", val reportCity: String = "Dhaka", val reportDescription: String = "", val reportMoneyLost: String = "", val reportIncidentDate: String = "24 Aug 2026", val reportIsAnonymous: Boolean = false, val evidenceList: List = emptyList(), val reportErrors: Map = emptyMap(), val isSubmittingReport: Boolean = false, val submittedReportId: String? = null, // Admin Review Panel val adminSelectedTab: Int = 0, // 0: Pending, 1: Verified, 2: Rejected val adminReviewingReportId: String? = null, val adminNotesInput: String = "" ) class SatarkViewModel(private val repository: SatarkRepository) : ViewModel() { private val _uiState = MutableStateFlow(UiState()) val uiState: StateFlow = _uiState.asStateFlow() init { viewModelScope.launch { repository.initializeSeedDataIfEmpty() } viewModelScope.launch { combine( repository.allCompanies, repository.allReports, repository.allWarnings, repository.allNotifications ) { companies, reports, warnings, notifications -> _uiState.update { current -> current.copy( companies = companies, reports = reports, publicWarnings = warnings, notifications = notifications, unreadNotificationCount = notifications.count { !it.isRead }, selectedCompany = if (current.selectedCompany != null) { companies.find { it.id == current.selectedCompany.id } ?: current.selectedCompany } else null ) } }.collect() } } fun navigateTo(screen: Screen) { _uiState.update { current -> current.copy( previousScreen = current.currentScreen, currentScreen = screen ) } } fun navigateBack() { _uiState.update { current -> val prev = current.previousScreen ?: Screen.HOME current.copy( currentScreen = if (current.currentScreen == Screen.HOME) Screen.HOME else prev, previousScreen = null ) } } fun toggleLanguage() { _uiState.update { it.copy( currentLanguage = if (it.currentLanguage == AppLanguage.BN) AppLanguage.EN else AppLanguage.BN ) } } fun setLanguage(lang: AppLanguage) { _uiState.update { it.copy(currentLanguage = lang) } } fun completeSplash() { navigateTo(Screen.ONBOARDING) } fun completeOnboarding() { navigateTo(Screen.AUTH) } fun setAuthenticatedUser(name: String, phone: String, isNid: Boolean) { _uiState.update { it.copy( userName = name.ifBlank { "Mohammad Shakib" }, userPhone = phone.ifBlank { "+880 1712-345678" }, isNidVerified = isNid, currentScreen = Screen.HOME ) } } fun selectCompany(companyId: String) { val found = _uiState.value.companies.find { it.id == companyId } _uiState.update { it.copy( selectedCompany = found, currentScreen = Screen.COMPANY_PROFILE, previousScreen = it.currentScreen ) } } fun selectWarning(warningId: String?) { _uiState.update { it.copy( selectedWarningId = warningId, currentScreen = Screen.PUBLIC_WARNINGS ) } } fun startReportWithEntity(entityName: String) { _uiState.update { it.copy( reportStep = 1, reportTargetName = entityName, reportContactInfo = "", reportDescription = "", reportMoneyLost = "", evidenceList = emptyList(), reportErrors = emptyMap(), submittedReportId = null, currentScreen = Screen.REPORT_FORM, previousScreen = it.currentScreen ) } } fun updateReportFields( targetName: String? = null, contactInfo: String? = null, category: String? = null, city: String? = null, description: String? = null, moneyLost: String? = null, isAnonymous: Boolean? = null, reporterName: String? = null, reporterPhone: String? = null ) { _uiState.update { current -> current.copy( reportTargetName = targetName ?: current.reportTargetName, reportContactInfo = contactInfo ?: current.reportContactInfo, reportCategory = category ?: current.reportCategory, reportCity = city ?: current.reportCity, reportDescription = description ?: current.reportDescription, reportMoneyLost = moneyLost ?: current.reportMoneyLost, reportIsAnonymous = isAnonymous ?: current.reportIsAnonymous, reportErrors = emptyMap() ) } } fun proceedToProofUpload() { val current = _uiState.value val errors = mutableMapOf() if (current.reportTargetName.trim().isBlank()) { errors["targetName"] = if (current.currentLanguage == AppLanguage.BN) "অভিযুক্ত ব্যক্তি বা প্রতিষ্ঠানের নাম দিন" else "Entity name is required" } if (current.reportContactInfo.trim().isBlank()) { errors["contactInfo"] = if (current.currentLanguage == AppLanguage.BN) "মোবাইল, বিকাশ নম্বর অথবা ফেসবুক পেজ লিংক দিন" else "Contact info or URL is required" } if (current.reportDescription.trim().length < 15) { errors["description"] = if (current.currentLanguage == AppLanguage.BN) "কমপক্ষে ১৫ অক্ষরে বিস্তারিত বিবরণ লিখুন" else "Please describe in at least 15 characters" } if (errors.isNotEmpty()) { _uiState.update { it.copy(reportErrors = errors) } } else { _uiState.update { it.copy( reportStep = 2, reportErrors = emptyMap(), currentScreen = Screen.PROOF_UPLOAD ) } } } fun backToReportStep1() { _uiState.update { it.copy( reportStep = 1, currentScreen = Screen.REPORT_FORM ) } } fun addEvidence(type: String, title: String, note: String) { val newItem = EvidenceItem( id = "EVID-${System.currentTimeMillis()}", title = title, type = type, timestamp = "24 Aug 2026", note = note ) _uiState.update { it.copy(evidenceList = it.evidenceList + newItem) } } fun removeEvidence(id: String) { _uiState.update { it.copy(evidenceList = it.evidenceList.filterNot { item -> item.id == id }) } } fun submitReport() { val current = _uiState.value val generatedId = "BD-SCAM-${(8950..9999).random()}" val lost = current.reportMoneyLost.toDoubleOrNull() ?: 0.0 val newReport = ScamReport( id = generatedId, targetEntityName = current.reportTargetName.trim(), contactInfo = current.reportContactInfo.trim(), scamCategory = current.reportCategory, city = current.reportCity, incidentDescription = current.reportDescription.trim(), moneyLostBdt = lost, dateReported = "24 Aug 2026", incidentDate = current.reportIncidentDate, status = ReportStatus.PENDING_REVIEW, isAnonymous = current.reportIsAnonymous, reporterName = if (current.reportIsAnonymous) "Anonymous Citizen" else current.userName, reporterPhone = if (current.reportIsAnonymous) "+880 1***-***" else current.userPhone, adminNotes = "Under initial triage by Satark BD cyber cell." ) viewModelScope.launch { _uiState.update { it.copy(isSubmittingReport = true) } repository.submitReport(newReport) _uiState.update { it.copy( isSubmittingReport = false, reportStep = 3, submittedReportId = generatedId, searchTrackingId = generatedId ) } } } fun resetReportForm() { _uiState.update { it.copy( reportStep = 1, reportTargetName = "", reportContactInfo = "", reportDescription = "", reportMoneyLost = "", evidenceList = emptyList(), reportErrors = emptyMap(), submittedReportId = null ) } } fun setSearchQuery(query: String) { _uiState.update { it.copy(searchQuery = query) } } fun setCategoryFilter(cat: String?) { _uiState.update { it.copy(selectedCategoryFilter = cat) } } fun setDivisionFilter(div: String?) { _uiState.update { it.copy(selectedDivisionFilter = div) } } fun setRiskFilter(risk: VerificationStatus?) { _uiState.update { it.copy(selectedRiskFilter = risk) } } fun setSearchTrackingId(id: String) { _uiState.update { it.copy(searchTrackingId = id) } } fun toggleAdminMode() { _uiState.update { it.copy(isAdminMode = !it.isAdminMode) } } fun setAdminTab(tab: Int) { _uiState.update { it.copy(adminSelectedTab = tab, adminReviewingReportId = null) } } fun selectReportForAdminReview(reportId: String?) { _uiState.update { it.copy(adminReviewingReportId = reportId, adminNotesInput = "") } } fun setAdminNotesInput(notes: String) { _uiState.update { it.copy(adminNotesInput = notes) } } fun approveReport(reportId: String, publishWarning: Boolean) { viewModelScope.launch { val note = _uiState.value.adminNotesInput.ifBlank { "Verified with documentary evidence and transaction receipts." } val status = if (publishWarning) ReportStatus.VERIFIED_WARNING_ISSUED else ReportStatus.LEGAL_ESCALATION repository.updateReportStatus(reportId, status, note, isPublicAlert = publishWarning) _uiState.update { it.copy(adminReviewingReportId = null) } } } fun rejectReport(reportId: String) { viewModelScope.launch { val note = _uiState.value.adminNotesInput.ifBlank { "Insufficient proof provided." } repository.updateReportStatus(reportId, ReportStatus.REJECTED, note, isPublicAlert = false) _uiState.update { it.copy(adminReviewingReportId = null) } } } fun markNotificationRead(id: String) { viewModelScope.launch { repository.markAllNotificationsRead() } } fun logout() { _uiState.update { it.copy( userName = "Guest Citizen", userPhone = "+880 1700-000000", isNidVerified = false, currentScreen = Screen.AUTH ) } } } class SatarkViewModelFactory(private val repository: SatarkRepository) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { if (modelClass.isAssignableFrom(SatarkViewModel::class.java)) { return SatarkViewModel(repository) as T } throw IllegalArgumentException("Unknown ViewModel class") } }