package com.dmc.callcrm.data import android.Manifest import android.content.Context import android.content.pm.PackageManager import android.provider.CallLog import androidx.core.content.ContextCompat /** Reads the device CallLog and produces the data shown in the employee UI. */ class CallStats(private val ctx: Context) { data class CallItem( val number: String, val name: String?, val type: Int, // CallLog.Calls TYPE val dateMs: Long, val durationSec: Int, val simSlot: Int? ) data class Analytics( val total: Int = 0, val totalDur: Long = 0, val incoming: Int = 0, val incomingDur: Long = 0, val outgoing: Int = 0, val outgoingDur: Long = 0, val missed: Int = 0, val rejected: Int = 0, val neverAttended: Int = 0 ) data class ContactItem(val number: String, val name: String?, val totalCalls: Int) private fun ok() = ContextCompat.checkSelfPermission(ctx, Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED /** Most recent calls (optionally filtered by type: 1 in, 2 out, 3 missed). */ fun recent(limit: Int = 300, typeFilter: Int? = null): List { if (!ok()) return emptyList() val proj = arrayOf( CallLog.Calls.NUMBER, CallLog.Calls.CACHED_NAME, CallLog.Calls.TYPE, CallLog.Calls.DATE, CallLog.Calls.DURATION, CallLog.Calls.PHONE_ACCOUNT_ID ) val sel = typeFilter?.let { "${CallLog.Calls.TYPE} = ?" } val args = typeFilter?.let { arrayOf(it.toString()) } val out = ArrayList() ctx.contentResolver.query( CallLog.Calls.CONTENT_URI, proj, sel, args, "${CallLog.Calls.DATE} DESC" )?.use { c -> val iNum = c.getColumnIndex(CallLog.Calls.NUMBER) val iName = c.getColumnIndex(CallLog.Calls.CACHED_NAME) val iType = c.getColumnIndex(CallLog.Calls.TYPE) val iDate = c.getColumnIndex(CallLog.Calls.DATE) val iDur = c.getColumnIndex(CallLog.Calls.DURATION) while (c.moveToNext() && out.size < limit) { out.add( CallItem( number = c.getString(iNum) ?: "Unknown", name = if (iName >= 0) c.getString(iName) else null, type = c.getInt(iType), dateMs = c.getLong(iDate), durationSec = c.getInt(iDur), simSlot = null ) ) } } return out } /** Aggregate analytics for a date range. */ fun analytics(fromMs: Long, toMs: Long): Analytics { if (!ok()) return Analytics() val proj = arrayOf(CallLog.Calls.TYPE, CallLog.Calls.DATE, CallLog.Calls.DURATION) val sel = "${CallLog.Calls.DATE} BETWEEN ? AND ?" val args = arrayOf(fromMs.toString(), toMs.toString()) var total = 0; var td = 0L var inc = 0; var incD = 0L; var out = 0; var outD = 0L var missed = 0; var rej = 0; var never = 0 ctx.contentResolver.query(CallLog.Calls.CONTENT_URI, proj, sel, args, null)?.use { c -> val iType = c.getColumnIndex(CallLog.Calls.TYPE) val iDur = c.getColumnIndex(CallLog.Calls.DURATION) while (c.moveToNext()) { val t = c.getInt(iType); val d = c.getInt(iDur) total++; td += d when (t) { CallLog.Calls.INCOMING_TYPE -> if (d > 0) { inc++; incD += d } else never++ CallLog.Calls.OUTGOING_TYPE -> { out++; outD += d } CallLog.Calls.MISSED_TYPE -> missed++ CallLog.Calls.REJECTED_TYPE -> rej++ } } } return Analytics(total, td, inc, incD, out, outD, missed, rej, never) } /** Contacts aggregated by number, most-called first. */ fun contacts(limit: Int = 200): List { if (!ok()) return emptyList() val proj = arrayOf(CallLog.Calls.NUMBER, CallLog.Calls.CACHED_NAME) val counts = LinkedHashMap>() ctx.contentResolver.query( CallLog.Calls.CONTENT_URI, proj, null, null, "${CallLog.Calls.DATE} DESC" )?.use { c -> val iNum = c.getColumnIndex(CallLog.Calls.NUMBER) val iName = c.getColumnIndex(CallLog.Calls.CACHED_NAME) while (c.moveToNext()) { val num = c.getString(iNum) ?: continue val name = if (iName >= 0) c.getString(iName) else null val prev = counts[num] counts[num] = Pair(prev?.first ?: name, (prev?.second ?: 0) + 1) } } return counts.entries .map { ContactItem(it.key, it.value.first, it.value.second) } .sortedByDescending { it.totalCalls } .take(limit) } }