package com.simplemobiletools.commons.helpers

import android.annotation.SuppressLint
import android.content.Context
import android.net.Uri
import android.provider.CallLog.Calls
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.models.RecentCall
import com.simplemobiletools.commons.models.SIMAccount
import com.simplemobiletools.commons.models.contacts.Contact

class RecentsHelperCommon(private val context: Context) {
    private val COMPARABLE_PHONE_NUMBER_LENGTH = 9
    private val QUERY_LIMIT = 200
    private val contentUri = Calls.CONTENT_URI

    /**
     * 获取导出通话记录 .json文件
     */
    fun getRecentCalls(groupSubsequentCalls: Boolean, maxSize: Int = QUERY_LIMIT, callback: (MutableList<RecentCall>) -> Unit) {
        val privateCursor = context.getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true)
        ensureBackgroundThread {
            if (!context.hasPermission(PERMISSION_READ_CALL_LOG)) {
                callback(ArrayList())
                return@ensureBackgroundThread
            }

            ContactsHelper(context).getContacts(showOnlyContactsWithNumbers = true) { contacts: java.util.ArrayList<Contact> ->
                val privateContacts = MyContactsContentProvider.getContacts(context, privateCursor)
                if (privateContacts.isNotEmpty()) {
                    contacts.addAll(privateContacts)
                }
                getRecents(contacts, groupSubsequentCalls, maxSize, callback = callback)
            }
        }
    }

    @SuppressLint("NewApi")
    private inline fun getRecents(contacts: List<Contact>, groupSubsequentCalls: Boolean, maxSize: Int, callback: (MutableList<RecentCall>) -> Unit) {

        val recentCalls = mutableListOf<RecentCall>()
        var previousRecentCallFrom = ""
        var previousStartTS = 0
        val contactsNumbersMap = HashMap<String, String>()
        val contactPhotosMap = HashMap<String, String>()

        val projection = arrayOf(
            Calls._ID,
            Calls.NUMBER,
            Calls.CACHED_NAME,
            Calls.CACHED_PHOTO_URI,
            Calls.DATE,
            Calls.DURATION,
            Calls.TYPE,
            Calls.PHONE_ACCOUNT_ID,
            Calls.COUNTRY_ISO,
            Calls.IS_READ,
//            Calls.CACHED_MATCHED_NUMBER
        )

        val accountIdToSimIDMap = HashMap<String, Int>()
        context.getAvailableSIMCardLabels().forEach {
            accountIdToSimIDMap[it.handle.id] = it.id
        }

        val cursor = if (isNougatPlus()) {
            // https://issuetracker.google.com/issues/175198972?pli=1#comment6
            val limitedUri = contentUri.buildUpon()
                .appendQueryParameter(Calls.LIMIT_PARAM_KEY, QUERY_LIMIT.toString())
                .build()
            val sortOrder = "${Calls.DATE} DESC"
            context.contentResolver.query(limitedUri, projection, null, null, sortOrder)
        } else {
            val sortOrder = "${Calls.DATE} DESC LIMIT $QUERY_LIMIT"
            context.contentResolver.query(contentUri, projection, null, null, sortOrder)
        }

        val contactsWithMultipleNumbers = contacts.filter { it.phoneNumbers.size > 1 }
        val numbersToContactIDMap = HashMap<String, Int>()
        contactsWithMultipleNumbers.forEach { contact ->
            contact.phoneNumbers.forEach { phoneNumber ->
                numbersToContactIDMap[phoneNumber.value] = contact.contactId
                numbersToContactIDMap[phoneNumber.normalizedNumber] = contact.contactId
            }
        }

        cursor?.use {
            if (!cursor.moveToFirst()) {
                return@use
            }

            do {
                val id = cursor.getIntValue(Calls._ID)
                var isUnknownNumber = false
                val number = cursor.getStringValueOrNull(Calls.NUMBER)
                if (number == null || number == "-1") {
                    isUnknownNumber = true
                }

                var name = cursor.getStringValueOrNull(Calls.CACHED_NAME)
                if (name.isNullOrEmpty() || name == "-1") {
                    name = number.orEmpty()
                }

                if (name == number && !isUnknownNumber) {
                    if (contactsNumbersMap.containsKey(number)) {
                        name = contactsNumbersMap[number]!!
                    } else {
                        val normalizedNumber = number.normalizePhoneNumber()
                        if (normalizedNumber!!.length >= COMPARABLE_PHONE_NUMBER_LENGTH) {
                            name = contacts.filter { it.phoneNumbers.isNotEmpty() }.firstOrNull { contact ->
                                val curNumber = contact.phoneNumbers.first().normalizedNumber
                                if (curNumber.length >= COMPARABLE_PHONE_NUMBER_LENGTH) {
                                    if (curNumber.substring(curNumber.length - COMPARABLE_PHONE_NUMBER_LENGTH) == normalizedNumber.substring(
                                            normalizedNumber.length - COMPARABLE_PHONE_NUMBER_LENGTH
                                        )
                                    ) {
                                        contactsNumbersMap[number] = contact.getNameToDisplay()
                                        return@firstOrNull true
                                    }
                                }
                                false
                            }?.name ?: number
                        }
                    }
                }

                if (name.isEmpty() || name == "-1") {
                    name = "未知"
                }

                var photoUri = cursor.getStringValue(Calls.CACHED_PHOTO_URI) ?: ""
                if (photoUri.isEmpty() && !number.isNullOrEmpty()) {
                    if (contactPhotosMap.containsKey(number)) {
                        photoUri = contactPhotosMap[number]!!
                    } else {
                        val contact = contacts.firstOrNull { it.doesContainPhoneNumber(number) }
                        if (contact != null) {
                            photoUri = contact.photoUri
                            contactPhotosMap[number] = contact.photoUri
                        }
                    }
                }

                val startTS = (cursor.getLongValue(Calls.DATE) / 1000L).toInt()
                if (previousStartTS == startTS) {
                    continue
                } else {
                    previousStartTS = startTS
                }

                val duration = cursor.getIntValue(Calls.DURATION)
                val type = cursor.getIntValue(Calls.TYPE)
                val accountId = cursor.getStringValue(Calls.PHONE_ACCOUNT_ID)
                val simID = accountIdToSimIDMap[accountId] ?: -1
                val neighbourIDs = mutableListOf<Int>()
                var specificNumber = ""
                var specificType = ""
                val sfFlag = cursor.getStringValue(Calls.COUNTRY_ISO)
//                val export = cursor.getStringValue(Calls.IS_READ)
//                val syncHideNumber = cursor.getStringValue(Calls.CACHED_MATCHED_NUMBER)

                val contactIdWithMultipleNumbers = numbersToContactIDMap[number]
                if (contactIdWithMultipleNumbers != null) {
                    val specificPhoneNumber =
                        contacts.firstOrNull { it.contactId == contactIdWithMultipleNumbers }?.phoneNumbers?.firstOrNull { it.value == number }
                    if (specificPhoneNumber != null) {
                        specificNumber = specificPhoneNumber.value
                        specificType = context.getPhoneNumberTypeText(specificPhoneNumber.type, specificPhoneNumber.label)
                    }
                }

                val recentCall = RecentCall(
                    id = id,
                    phoneNumber = number.orEmpty(),//正常存储，加密放在结束通话
                    name = name,
                    photoUri = photoUri,
                    startTS = startTS,
                    duration = duration,
                    type = type,
                    neighbourIDs = neighbourIDs,
                    simID = simID,
                    specificNumber = specificNumber,
                    specificType = specificType,
                    isUnknownNumber = isUnknownNumber,
                    isShunFeng = sfFlag == "",
                    sfNumber = number.orEmpty(),
                    isExport = false,
//                    isHidePhoneNumber = syncNumber,
                )

                // if we have multiple missed calls from the same number, show it just once
                if (!groupSubsequentCalls || "$number$name$simID" != previousRecentCallFrom) {
                    recentCalls.add(recentCall)
                } else {
                    recentCalls.lastOrNull()?.neighbourIDs?.add(id)
                }

                previousRecentCallFrom = "$number$name$simID"
            } while (cursor.moveToNext() && recentCalls.size < maxSize)
        }

//        val blockedNumbers = context.getBlockedNumbers()
//
//        val recentResult = recentCalls
//            .filter { !context.isNumberBlocked(it.phoneNumber, blockedNumbers) }.toMutableList()
//        callback(recentResult)

        callback(recentCalls)
    }


    @SuppressLint("MissingPermission")
    fun Context.getAvailableSIMCardLabels(): List<SIMAccount> {
        val SIMAccounts = mutableListOf<SIMAccount>()
        try {
            telecomManager.callCapablePhoneAccounts.forEachIndexed { index, account ->
                val phoneAccount = telecomManager.getPhoneAccount(account)
                var label = phoneAccount.label.toString()
                var address = phoneAccount.address.toString()
                if (address.startsWith("tel:") && address.substringAfter("tel:").isNotEmpty()) {
                    address = Uri.decode(address.substringAfter("tel:"))
                    label += " ($address)"
                }

                val SIM = SIMAccount(index + 1, phoneAccount.accountHandle, label, address.substringAfter("tel:"))
                SIMAccounts.add(SIM)
            }
        } catch (ignored: Exception) {
        }
        return SIMAccounts
    }

}
