package com.example.data.repository import android.content.Context import com.example.data.engine.CampaignSendingEngine import com.example.data.engine.ContactImportValidator import com.example.data.engine.ImportValidationReport import com.example.data.local.AppDatabase import com.example.data.local.entity.AuditLogEntity import com.example.data.local.entity.CampaignEntity import com.example.data.local.entity.CampaignRecipientEntity import com.example.data.local.entity.ConsumerAccountEntity import com.example.data.local.entity.ContactCategoryEntity import com.example.data.local.entity.ContactEntity import com.example.data.local.entity.ConversationMessageEntity import com.example.data.local.entity.LeadEntity import com.example.data.local.entity.ProductEntity import com.example.data.local.entity.SubscriptionPlanEntity import com.example.data.local.entity.WhatsAppTemplateEntity import com.example.data.meta.MetaCloudApiService import com.example.data.meta.MetaComponent import com.example.data.meta.MetaLanguage import com.example.data.meta.MetaParameter import com.example.data.meta.MetaSendMessageRequest import com.example.data.meta.MetaTemplatePayload import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.withContext class MarketingRepository(private val db: AppDatabase) { val sendingEngine = CampaignSendingEngine(db) val account: Flow = db.consumerAccountDao().getAccount() val categories: Flow> = db.contactCategoryDao().getAllCategories() val allContacts: Flow> = db.contactDao().getAllContacts() val eligibleContacts: Flow> = db.contactDao().getEligibleOptedInContacts() val consumerContacts: Flow> = db.contactDao().getConsumerContacts() val eligibleConsumerContacts: Flow> = db.contactDao().getEligibleConsumerContacts() val partners: Flow> = db.partnerDao().getAllPartners() val pendingContacts: Flow> = db.contactDao().getPendingApprovalContacts() val totalContactCount: Flow = db.contactDao().getTotalContactCount() val eligibleContactCount: Flow = db.contactDao().getEligibleContactCount() val templates: Flow> = db.whatsAppTemplateDao().getAllTemplates() val campaigns: Flow> = db.campaignDao().getAllCampaigns() val products: Flow> = db.productDao().getAllProducts() val leads: Flow> = db.leadDao().getAllLeads() val conversations: Flow> = db.conversationDao().getAllMessages() val auditLogs: Flow> = db.auditLogDao().getAllLogs() val subscriptionPlans: Flow> = db.subscriptionPlanDao().getAllPlans() suspend fun seedInitialDataIfEmpty() = withContext(Dispatchers.IO) { val existingAccount = db.consumerAccountDao().getAccount().firstOrNull() val dewaAccount = (existingAccount ?: ConsumerAccountEntity()).copy( businessName = "DEWA Gram Udhyog Pvt Ltd", mobileNumber = "+919461321162", email = "contact@sdadigital.in", gstNumber = "06AAJCD0975H1ZK", address = "Gali No 4, Uttam Nagar Loharu Road, Bhiwani 127021 HR", metaPhoneNumberId = "913349665192073", metaWabaId = "1378746380406848", metaAccessTokenMasked = "EAAl6rWdth7YBSvrGsUqF53H26vetTv1BmfGssD9wZAFW9XkTcJIawKkKEdJDD6GSgqKhGlfOceMiZCR4ilLtszYanJhMRZBdrj9fyXcZAzvMHupNGD5VEyzAgwSs649OBBtYSLp5HVFU4no0ZBEfnm5c9cLepoZCZByZAS6yVpl9CUXJlzdU8kdxVlg4VgAK4C745C7Q5nQKn7zLF65h8O7jVZCIuu2yM2IGTIMJhn40gZC6mzfRGfmnOjNr3IJ3JeuzgroDsZD", subscriptionPlan = "Enterprise Pro", status = "ACTIVE" ) db.consumerAccountDao().insertOrUpdate(dewaAccount) // Ensure User's 5 Specific Contacts are ALWAYS in the database val userProvidedContacts = listOf( ContactEntity( countryCode = "91", mobileNumber = "9355321162", e164Phone = "+919355321162", customerName = "Mrs Bimla", businessName = "DEWA Gram Udhyog", email = "bimla@sdadigital.in", city = "Bhiwani", district = "Bhiwani", state = "Haryana", pinCode = "127021", categoryId = 1, categoryName = "Consumer Upload List", productInterest = "Gram Udhyog Products", tags = "consumer;priority", optInStatus = "OPTED_IN", consentSource = "Consumer Consent Record", consentDate = "2026-10-16", customerNotes = "Direct registered consumer - Verified WhatsApp Opt-in", isApprovedByAdmin = true, isConsumerUpload = true ), ContactEntity( countryCode = "91", mobileNumber = "9315321162", e164Phone = "+919315321162", customerName = "Mr. Dinesh Kumar", businessName = "DEWA Gram Udhyog", email = "dinesh@sdadigital.in", city = "Bhiwani", district = "Bhiwani", state = "Haryana", pinCode = "127021", categoryId = 1, categoryName = "Consumer Upload List", productInterest = "Gram Udhyog Products", tags = "consumer;verified", optInStatus = "OPTED_IN", consentSource = "Consumer Consent Record", consentDate = "2026-10-16", customerNotes = "Verified contact list - Verified WhatsApp Opt-in", isApprovedByAdmin = true, isConsumerUpload = true ), ContactEntity( countryCode = "91", mobileNumber = "6000072002", e164Phone = "+916000072002", customerName = "Vikash Verma", businessName = "DEWA Gram Udhyog", email = "vikash.verma@gmail.com", city = "Bhiwani", district = "Bhiwani", state = "Haryana", pinCode = "127021", categoryId = 1, categoryName = "Consumer Upload List", productInterest = "Gram Udhyog Equipment", tags = "consumer", optInStatus = "OPTED_IN", consentSource = "Consumer Consent Record", consentDate = "2026-10-16", customerNotes = "Opted-in consumer contact", isApprovedByAdmin = true, isConsumerUpload = true ), ContactEntity( countryCode = "91", mobileNumber = "9812405817", e164Phone = "+919812405817", customerName = "Ajay Kumar", businessName = "DEWA Gram Udhyog", email = "ajay.kumar@gmail.com", city = "Bhiwani", district = "Bhiwani", state = "Haryana", pinCode = "127021", categoryId = 1, categoryName = "Consumer Upload List", productInterest = "Bulk Consumer Catalog", tags = "consumer;retail", optInStatus = "OPTED_IN", consentSource = "Consumer Consent Record", consentDate = "2026-10-16", customerNotes = "Regular consumer", isApprovedByAdmin = true, isConsumerUpload = true ), ContactEntity( countryCode = "91", mobileNumber = "7600910000", e164Phone = "+917600910000", customerName = "Sudhir Malik", businessName = "DEWA Gram Udhyog", email = "sudhir.malik@gmail.com", city = "Bhiwani", district = "Bhiwani", state = "Haryana", pinCode = "127021", categoryId = 1, categoryName = "Consumer Upload List", productInterest = "Rural Gram Udhyog Solns", tags = "consumer", optInStatus = "OPTED_IN", consentSource = "Consumer Consent Record", consentDate = "2026-10-16", customerNotes = "Verified opt-in WhatsApp", isApprovedByAdmin = true, isConsumerUpload = true ) ) for (contact in userProvidedContacts) { val existing = db.contactDao().findByPhone(contact.e164Phone) if (existing == null) { db.contactDao().insert(contact) } else { db.contactDao().update( existing.copy( customerName = contact.customerName, district = contact.district, state = contact.state, pinCode = contact.pinCode, optInStatus = "OPTED_IN", isApprovedByAdmin = true, isConsumerUpload = true ) ) } } if (existingAccount == null) { // Categories val initialCategories = listOf( ContactCategoryEntity(1, "Solar Dealers and Distributors", "B2B authorized channel partners & retailers", "#008069"), ContactCategoryEntity(2, "Solar Installation Customers", "Residential and commercial rooftop owners", "#0284C7"), ContactCategoryEntity(3, "Wholesale Buyers", "Industrial procurers, cold storage & factories", "#7C3AED"), ContactCategoryEntity(4, "Retail Customers", "Walk-in retail buyers & consumer solar products", "#D97706"), ContactCategoryEntity(5, "Franchise Enquiries", "Prospective territory franchise partners", "#E11D48"), ContactCategoryEntity(6, "Service and Maintenance", "AMC and annual inverter inspection clients", "#059669") ) db.contactCategoryDao().insertAll(initialCategories) // Contacts - Seeded Consumer Contact List val initialContacts = listOf( ContactEntity( countryCode = "91", mobileNumber = "9823011223", e164Phone = "+919823011223", customerName = "Aarav Sharma", businessName = "", email = "aarav.sharma@gmail.com", city = "Pune", district = "Pune", state = "Maharashtra", pinCode = "411001", categoryId = 1, categoryName = "Consumer Upload List", productInterest = "5kW Hybrid Inverter", tags = "consumer;rooftop", optInStatus = "OPTED_IN", consentSource = "Consumer CSV Upload", consentDate = "2026-10-10", customerNotes = "Consumer requested home solar installation", isApprovedByAdmin = true, isConsumerUpload = true ), ContactEntity( countryCode = "91", mobileNumber = "9876543201", e164Phone = "+919876543201", customerName = "Pooja Verma", businessName = "", email = "pooja.verma@yahoo.com", city = "Ahmedabad", district = "Ahmedabad", state = "Gujarat", pinCode = "380015", categoryId = 1, categoryName = "Consumer Upload List", productInterest = "3kW Rooftop Package", tags = "consumer;residential", optInStatus = "OPTED_IN", consentSource = "Consumer CSV Upload", consentDate = "2026-10-02", customerNotes = "Site audit requested", isApprovedByAdmin = true, isConsumerUpload = true ), ContactEntity( countryCode = "91", mobileNumber = "9812345678", e164Phone = "+919812345678", customerName = "Vikram Singhania", businessName = "", email = "vikram.s@outlook.com", city = "Indore", district = "Indore", state = "Madhya Pradesh", pinCode = "452001", categoryId = 1, categoryName = "Consumer Upload List", productInterest = "Solar Hot Water Heater 200L", tags = "consumer;heater", optInStatus = "OPTED_IN", consentSource = "Consumer CSV Upload", consentDate = "2026-09-20", customerNotes = "Domestic water heater requirement", isApprovedByAdmin = true, isConsumerUpload = true ), ContactEntity( countryCode = "91", mobileNumber = "9765432190", e164Phone = "+919765432190", customerName = "Rohan Deshmukh", businessName = "", email = "rohan.d@gmail.com", city = "Nagpur", district = "Nagpur", state = "Maharashtra", pinCode = "440001", categoryId = 1, categoryName = "Consumer Upload List", productInterest = "Solar Submersible Pump 5HP", tags = "consumer;agriculture", optInStatus = "OPTED_IN", consentSource = "Consumer CSV Upload", consentDate = "2026-09-28", customerNotes = "Farm power backup", isApprovedByAdmin = true, isConsumerUpload = true ), ContactEntity( countryCode = "91", mobileNumber = "9988776655", e164Phone = "+919988776655", customerName = "", // Empty consumer name to test fallback: Mobile Number and District Name businessName = "", email = "", city = "Nashik", district = "Nashik", state = "", pinCode = "", categoryId = 1, categoryName = "Consumer Upload List", productInterest = "", tags = "consumer", optInStatus = "OPTED_IN", consentSource = "Consumer CSV Upload", consentDate = "2026-10-14", customerNotes = "", isApprovedByAdmin = true, isConsumerUpload = true ) ) db.contactDao().insertAll(initialContacts) // Seed Initial Partners val initialPartners = listOf( com.example.data.local.entity.PartnerEntity( 1, "MahaSolar Channel Partners", "MahaSolar Infra Pvt Ltd", "+919822001122", "Pune", "Maharashtra", "411004", "Channel Partner", true ), com.example.data.local.entity.PartnerEntity( 2, "Gujarat Sun Power Network", "Gujarat Solar Distributors", "+919879003344", "Ahmedabad", "Gujarat", "380009", "Regional Partner", true ), com.example.data.local.entity.PartnerEntity( 3, "Central India Solar Services", "Vindhya Renewable Tech", "+919425005566", "Indore", "Madhya Pradesh", "452010", "Installation Partner", false ) ) db.partnerDao().insertAll(initialPartners) // Templates val initialTemplates = listOf( WhatsAppTemplateEntity( id = "festive_solar_launch", templateName = "festive_solar_launch", category = "MARKETING", headerType = "IMAGE", headerContent = "https://images.unsplash.com/photo-1509391365360-2e959784a276?w=800", bodyText = "Dear {{1}},\n\nIlluminate your business with SunPower's Mega Festive Offer! Get an exclusive {{2}} on all On-Grid and Hybrid Solar Inverters this week.\n\nEnjoy 10-year comprehensive warranty, zero processing fees, and free site feasibility inspection.", footerText = "Reply STOP to opt-out", buttonsJson = "[{\"type\":\"QUICK_REPLY\",\"text\":\"Chat with Sales\"},{\"type\":\"URL\",\"text\":\"Download Catalogue\",\"url\":\"https://sunpower.example.com/festive\"}]", metaStatus = "APPROVED" ), WhatsAppTemplateEntity( id = "dealer_franchise_invite", templateName = "dealer_franchise_invite", category = "MARKETING", headerType = "TEXT", headerContent = "SUNPOWER DEALERSHIP PARTNERSHIP", bodyText = "Hello {{1}},\n\nExpand your revenue by becoming an authorized SunPower Solar Channel Partner in {{2}}. High distributor margins, dedicated marketing support, and leads in your region.", footerText = "Official WhatsApp Business Partner", buttonsJson = "[{\"type\":\"QUICK_REPLY\",\"text\":\"Request Franchise Kit\"},{\"type\":\"PHONE_NUMBER\",\"text\":\"Call Regional Mgr\",\"phone\":\"+919876543210\"}]", metaStatus = "APPROVED" ), WhatsAppTemplateEntity( id = "service_maintenance_alert", templateName = "service_maintenance_alert", category = "UTILITY", headerType = "DOCUMENT", headerContent = "https://sunpower.example.com/docs/inverter-guide.pdf", bodyText = "Hello {{1}},\n\nThis is a friendly reminder for your scheduled solar inverter preventive checkup for system {{2}}. Ensure peak power efficiency before summer.", footerText = "SunPower Technical Service Team", buttonsJson = "[{\"type\":\"QUICK_REPLY\",\"text\":\"Confirm Date\"},{\"type\":\"QUICK_REPLY\",\"text\":\"Reschedule\"}]", metaStatus = "APPROVED" ) ) db.whatsAppTemplateDao().insertAll(initialTemplates) // Products val initialProducts = listOf( ProductEntity( 1, "SunPower 5kW Hybrid Inverter G2", "INV-5000-HYB", "Inverters", 78500.0, 15, "Dual MPPT, IP65 waterproof, Wi-Fi telemetry & 10 yr warranty", "https://sunpower.example.com/docs/inv5k.pdf", "https://wa.me/919876543210?text=Interested%20in%205kW%20Inverter" ), ProductEntity( 2, "550W Monocrystalline PERC Solar Panel", "PNL-550-MONO", "Solar Panels", 14200.0, 10, "High efficiency 21.3% German cells, anti-PID and 25-yr linear power warranty", "https://sunpower.example.com/docs/panel550.pdf", "https://wa.me/919876543210?text=Interested%20in%20550W%20Panel" ), ProductEntity( 3, "SunPower 3kW Complete Rooftop Package", "PKG-3KW-ROOF", "Complete Kits", 165000.0, 18, "Turnkey rooftop installation including net metering, structure and earthing", "https://sunpower.example.com/docs/pkg3k.pdf", "https://wa.me/919876543210?text=Interested%20in%203kW%20Kit" ), ProductEntity( 4, "Solar Hot Water Heater 200 LPD", "HTR-200-SS", "Solar Thermal", 28900.0, 12, "Food grade SS316 tank with vacuum tube glass collectors", "https://sunpower.example.com/docs/heater200.pdf", "https://wa.me/919876543210?text=Interested%20in%20Solar%20Heater" ) ) db.productDao().insertAll(initialProducts) // Campaigns val initialCampaigns = listOf( CampaignEntity( 1, "Diwali Commercial Solar Blast", "Targeted bulk WhatsApp campaign to verified solar distributors", "festive_solar_launch", "festive_solar_launch", "Solar Dealers and Distributors", targetCount = 450, eligibleCount = 428, sentCount = 428, deliveredCount = 419, readCount = 372, failedCount = 9, status = "COMPLETED", scheduledTime = "2026-10-10", variableValues = "25% Festive Discount" ), CampaignEntity( 2, "Western Region Franchise Drive", "Onboarding new district distributors across Gujarat & Maharashtra", "dealer_franchise_invite", "dealer_franchise_invite", "Franchise Enquiries, Wholesale Buyers", targetCount = 180, eligibleCount = 175, sentCount = 175, deliveredCount = 170, readCount = 138, failedCount = 5, status = "COMPLETED", scheduledTime = "2026-10-14", variableValues = "Maharashtra & Gujarat" ) ) for (c in initialCampaigns) { db.campaignDao().insert(c) } // Leads val initialLeads = listOf( LeadEntity( 1, "Mahesh Kadam", "+919822334455", "Kadam Cold Storage", "Diwali Commercial Solar Blast", "100kW Industrial Microgrid", "Customer clicked Quick Reply on campaign message asking for site visit", status = "QUOTATION_SENT", assignedTo = "Rahul Sharma", followUpDate = "2026-10-18", conversionValue = 3800000.0, salesNotes = "Sent technical feasibility assessment. Expecting purchase order next Monday." ), LeadEntity( 2, "Anita Patel", "+919712345600", "Patel Electricals Surat", "Western Region Franchise Drive", "Exclusive Territory Dealership", "Inquired about dealer margin and minimum stock quantity", status = "INTERESTED", assignedTo = "Priya Nair", followUpDate = "2026-10-19", conversionValue = 750000.0, salesNotes = "Scheduled video presentation with Territory Head." ), LeadEntity( 3, "Devendra Joshi", "+919933441122", "Joshi Agro Processing", "Website Form / Direct", "Solar Submersible Pump 7.5HP", "Needs water pump for sugarcane plantation in Solapur", status = "FOLLOW_UP", assignedTo = "Rahul Sharma", followUpDate = "2026-10-21", conversionValue = 285000.0, salesNotes = "Subsidy application approved by MSEDCL." ) ) db.leadDao().insertAll(initialLeads) // Conversation Messages val initialMessages = listOf( ConversationMessageEntity( phone = "+919823011223", customerName = "Aarav Sharma", messageText = "Hello Aarav Sharma, Illuminate your business with SunPower's Mega Festive Offer! Get 25% Off on all Inverters. Reply STOP to opt-out.", isIncoming = false, deliveryStatus = "READ" ), ConversationMessageEntity( phone = "+919823011223", customerName = "Aarav Sharma", messageText = "Hi SunPower team! We have 4 commercial rooftop queries this week. Can you email the 5kW and 10kW dealer rate card?", isIncoming = true, deliveryStatus = "READ", isInteractiveReply = true, buttonPayload = "Chat with Sales" ), ConversationMessageEntity( phone = "+919823011223", customerName = "Aarav Sharma", messageText = "Certainly Aarav! I've attached our updated B2B price matrix and dispatched 2 sample inverters to your Pune depot.", isIncoming = false, deliveryStatus = "DELIVERED" ) ) db.conversationDao().insertAll(initialMessages) // Subscription plans val initialPlans = listOf( SubscriptionPlanEntity("starter", "Starter Plan", 1999.0, 2500, 5000, 1, "Meta Cloud API, CSV Import, Template Messages"), SubscriptionPlanEntity("business", "Business Plan", 4999.0, 15000, 25000, 3, "All Starter features, Multi-Category, Auto Lead CRM, Webhook Sync"), SubscriptionPlanEntity("pro", "Professional Plan", 9999.0, 50000, 100000, 8, "All Business features, High-throughput sending, Product Catalogues, Priority Queue"), SubscriptionPlanEntity("enterprise", "Enterprise Custom", 24999.0, 250000, 500000, 25, "Unlimited Categories, Dedicated Meta WABA, Custom Webhook Workers, SLA Support") ) db.subscriptionPlanDao().insertAll(initialPlans) // Audit Logs db.auditLogDao().insert( AuditLogEntity( actionType = "SYSTEM_INITIALIZED", actorRole = "SUPER_ADMIN", description = "Enterprise Bulk Business WhatsApp Messaging Platform initialized. Meta Cloud API Graph v21.0 configured." ) ) } } suspend fun addTemplate(template: WhatsAppTemplateEntity) = withContext(Dispatchers.IO) { db.whatsAppTemplateDao().insert(template) db.auditLogDao().insert( AuditLogEntity( actionType = "TEMPLATE_CREATED", actorRole = "ADMIN", description = "Message template '${template.templateName}' submitted for Meta approval." ) ) } suspend fun importContactsFromCsv( csvText: String, defaultCategoryName: String, defaultCategoryId: Long ): ImportValidationReport = withContext(Dispatchers.IO) { val existingContacts = db.contactDao().getAllContacts().firstOrNull() ?: emptyList() val existingPhones = existingContacts.map { it.e164Phone }.toSet() val report = ContactImportValidator.parseCsvContent( csvText = csvText, existingPhones = existingPhones, defaultCategory = defaultCategoryName, defaultCategoryId = defaultCategoryId ) if (report.validContacts.isNotEmpty()) { db.contactDao().insertAll(report.validContacts) db.auditLogDao().insert( AuditLogEntity( actionType = "CONTACTS_UPLOADED", actorRole = "CONSUMER", description = "Uploaded ${report.totalRowsProcessed} records: ${report.validCount} valid, ${report.duplicateCount} duplicates, ${report.nonConsentingCount} missing consent." ) ) } report } suspend fun createAndLaunchCampaign( title: String, description: String, templateId: String, templateName: String, categoryNames: String, mediaUrl: String, variableValues: String, scope: CoroutineScope ): Long = withContext(Dispatchers.IO) { // Exclusively target Consumer contact list uploaded using CSV, excluding Vendors and Retailers val eligible = db.contactDao().getEligibleConsumerContacts().firstOrNull() ?: emptyList() val targetList = eligible.take(150) // Safe campaign batch val campaign = CampaignEntity( title = title, description = description, templateId = templateId, templateName = templateName, categoryNames = "Consumer Upload List (Excluding Vendors/Retailers)", targetCount = targetList.size, eligibleCount = targetList.size, sentCount = 0, deliveredCount = 0, readCount = 0, failedCount = 0, status = "QUEUED", mediaUrl = mediaUrl, variableValues = variableValues ) val campaignId = db.campaignDao().insert(campaign) val recipients = targetList.map { contact -> CampaignRecipientEntity( campaignId = campaignId, contactId = contact.id, phone = contact.e164Phone, customerName = contact.customerName, status = "QUEUED" ) } db.campaignRecipientDao().insertAll(recipients) db.auditLogDao().insert( AuditLogEntity( actionType = "CAMPAIGN_LAUNCHED", actorRole = "CONSUMER", description = "Launched campaign '$title' with ${recipients.size} recipients using template '$templateName'." ) ) // Launch sending engine in background sendingEngine.startCampaign(campaignId, scope) campaignId } suspend fun sendSingleReply(phone: String, customerName: String, messageText: String) = withContext(Dispatchers.IO) { db.conversationDao().insert( ConversationMessageEntity( phone = phone, customerName = customerName, messageText = messageText, isIncoming = false, deliveryStatus = "DELIVERED" ) ) } suspend fun updateLeadStatus(leadId: Long, newStatus: String) = withContext(Dispatchers.IO) { db.leadDao().updateLeadStatus(leadId, newStatus) db.auditLogDao().insert( AuditLogEntity( actionType = "LEAD_STATUS_UPDATED", actorRole = "CONSUMER", description = "Updated Lead #$leadId status to $newStatus." ) ) } suspend fun addNewLead(lead: LeadEntity) = withContext(Dispatchers.IO) { db.leadDao().insert(lead) } suspend fun approveContact(contactId: Long) = withContext(Dispatchers.IO) { db.contactDao().approveContact(contactId) db.auditLogDao().insert( AuditLogEntity( actionType = "CONTACT_APPROVED", actorRole = "ADMIN", description = "Admin approved contact record #$contactId." ) ) } suspend fun approveAllPendingContacts() = withContext(Dispatchers.IO) { db.contactDao().approveAllPending() db.auditLogDao().insert( AuditLogEntity( actionType = "BULK_CONTACTS_APPROVED", actorRole = "ADMIN", description = "Admin batch-approved all pending uploaded contact records." ) ) } suspend fun addCategory(name: String, description: String, colorHex: String) = withContext(Dispatchers.IO) { db.contactCategoryDao().insert( ContactCategoryEntity( name = name, description = description, colorHex = colorHex ) ) } suspend fun addProduct(product: ProductEntity) = withContext(Dispatchers.IO) { db.productDao().insert(product) } suspend fun updateAccountSettings(account: ConsumerAccountEntity) = withContext(Dispatchers.IO) { db.consumerAccountDao().insertOrUpdate(account) } suspend fun addPartner(partner: com.example.data.local.entity.PartnerEntity) = withContext(Dispatchers.IO) { db.partnerDao().insert(partner) db.auditLogDao().insert( AuditLogEntity( actionType = "PARTNER_ADDED", actorRole = "ADMIN", description = "Partner added: ${partner.name} (${partner.district}, ${partner.partnerType})." ) ) } suspend fun deletePartner(partner: com.example.data.local.entity.PartnerEntity) = withContext(Dispatchers.IO) { db.partnerDao().delete(partner) db.auditLogDao().insert( AuditLogEntity( actionType = "PARTNER_REMOVED", actorRole = "ADMIN", description = "Partner removed: ${partner.name}." ) ) } suspend fun togglePartnerActive(id: Long, isActive: Boolean) = withContext(Dispatchers.IO) { db.partnerDao().toggleActive(id, isActive) db.auditLogDao().insert( AuditLogEntity( actionType = if (isActive) "PARTNER_ACTIVATED" else "PARTNER_DEACTIVATED", actorRole = "ADMIN", description = "Partner #$id status set to ${if (isActive) "ACTIVE" else "DEACTIVE"}." ) ) } suspend fun toggleAccountStatus(isActive: Boolean) = withContext(Dispatchers.IO) { val account = db.consumerAccountDao().getAccount().firstOrNull() ?: return@withContext val newStatus = if (isActive) "ACTIVE" else "DEACTIVE" db.consumerAccountDao().insertOrUpdate(account.copy(status = newStatus)) db.auditLogDao().insert( AuditLogEntity( actionType = if (isActive) "ACCOUNT_ACTIVATED" else "ACCOUNT_DEACTIVATED", actorRole = "SUPER_ADMIN", description = "Account status updated to $newStatus." ) ) } private val metaApiClient = MetaCloudApiService.create() suspend fun testMetaApiConnection(): Pair = withContext(Dispatchers.IO) { val account = db.consumerAccountDao().getAccount().firstOrNull() ?: ConsumerAccountEntity() val token = if (account.metaAccessTokenMasked.startsWith("Bearer ")) { account.metaAccessTokenMasked } else { "Bearer ${account.metaAccessTokenMasked}" } try { val phoneResp = metaApiClient.getPhoneNumberDetails( phoneNumberId = account.metaPhoneNumberId, bearerToken = token ) val body = phoneResp.body() if (phoneResp.isSuccessful && body != null) { val phoneId = body.id ?: account.metaPhoneNumberId val disp = body.displayPhoneNumber ?: "Connected" val q = body.qualityRating ?: "GREEN" val msg = "Meta Verified! Phone ID: $phoneId, Display: $disp, Quality: $q" Pair(true, msg) } else { val err = phoneResp.errorBody()?.string() ?: "HTTP ${phoneResp.code()}" Pair(false, "Meta API Response: $err") } } catch (e: Exception) { Pair(false, "Connection error: ${e.localizedMessage}") } } suspend fun sendDirectWhatsAppMessage( recipientPhone: String, templateName: String, customerName: String, offerText: String ): Pair = withContext(Dispatchers.IO) { val account = db.consumerAccountDao().getAccount().firstOrNull() ?: ConsumerAccountEntity() val token = if (account.metaAccessTokenMasked.startsWith("Bearer ")) { account.metaAccessTokenMasked } else { "Bearer ${account.metaAccessTokenMasked}" } val request = MetaSendMessageRequest( to = recipientPhone, type = "template", template = MetaTemplatePayload( name = templateName.lowercase(), language = MetaLanguage("en_US"), components = listOf( MetaComponent( type = "body", parameters = listOf( MetaParameter(type = "text", text = customerName), MetaParameter(type = "text", text = offerText) ) ) ) ) ) try { val response = metaApiClient.sendMessage( phoneNumberId = account.metaPhoneNumberId, bearerToken = token, request = request ) if (response.isSuccessful) { val respBody = response.body() val messagesList = respBody?.messages val msgId = if (!messagesList.isNullOrEmpty()) messagesList[0].id else "wamid.success" db.consumerAccountDao().incrementQuotaUsed(1) db.conversationDao().insert( ConversationMessageEntity( phone = recipientPhone, customerName = customerName, messageText = "Template: $templateName - $offerText", isIncoming = false, deliveryStatus = "SENT" ) ) Pair(true, "Sent via Meta Cloud API! ID: $msgId") } else { val err = response.errorBody()?.string() ?: "HTTP ${response.code()}" Pair(false, "Meta Cloud API Error: $err") } } catch (e: Exception) { Pair(false, "Network error: ${e.localizedMessage}") } } suspend fun updateContactOptIn(contactId: Long, isOptedIn: Boolean) = withContext(Dispatchers.IO) { val status = if (isOptedIn) "OPTED_IN" else "OPTED_OUT" db.contactDao().updateOptInStatus(contactId, status) db.auditLogDao().insert( AuditLogEntity( actionType = "CONTACT_CONSENT_UPDATE", description = "Contact #$contactId consent status updated to $status", actorRole = "CONSUMER" ) ) } suspend fun deleteContact(contactId: Long) = withContext(Dispatchers.IO) { db.contactDao().deleteContactById(contactId) db.auditLogDao().insert( AuditLogEntity( actionType = "CONTACT_DELETION", description = "Contact #$contactId removed from consumer list", actorRole = "CONSUMER" ) ) } }