package com.xplora.contactprovider.provider

import android.annotation.SuppressLint
import android.content.ContentProvider
import android.content.ContentUris
import android.content.ContentValues
import android.content.UriMatcher
import android.net.Uri
import androidx.room.Room
import com.google.gson.Gson
import com.xplora.contactprovider.dao.BaseEntity
import com.xplora.contactprovider.dao.ContactDatabase
import com.xplora.contactprovider.dao.ContactInfo

class WatchContactProvider : ContentProvider() {
    companion object {
        private const val AUTHORITIES = "com.xplora.WatchContactProvider"
        private const val CONTENT_URI = "content://$AUTHORITIES"
        const val CONTACT_DIR = 0
        const val CONTACT_ITEM = 1
        const val CONTACT_MULTI = 2

        const val TABLE_NAME_CONTACT = "contact"
        const val TABLE_NAME_CONTACT_MULTI = "contact_multi"

        private val CONTACT_TABLE_URI = Uri.parse("$CONTENT_URI/$TABLE_NAME_CONTACT")!!
    }

    private var db: ContactDatabase? = null

    private val sUriMatcher by lazy {
        val matcher = UriMatcher(UriMatcher.NO_MATCH)
        matcher.addURI(AUTHORITIES, TABLE_NAME_CONTACT, CONTACT_DIR)
        matcher.addURI(AUTHORITIES, "$TABLE_NAME_CONTACT/#", CONTACT_ITEM)
        matcher.addURI(AUTHORITIES, TABLE_NAME_CONTACT_MULTI, CONTACT_MULTI)
        matcher
    }

    override fun onCreate() = context?.let {
        db = Room.databaseBuilder(it, ContactDatabase::class.java, TABLE_NAME_CONTACT)
            .build()
        true
    } ?: false

    @SuppressLint("Range")
    override fun query(
        uri: Uri,
        projection: Array<String>?,
        selection: String?,
        selectionArgs: Array<String>?,
        sortOrder: String?
    ) = db?.let { db ->
        val dao = db.contactDao()
        when (sUriMatcher.match(uri)) {
            CONTACT_DIR -> dao.query()
            CONTACT_ITEM -> dao.queryByIdForApp(ContentUris.parseId(uri))
            else -> null
        }?.let { c ->
            while (c.moveToNext()) {
                c.setNotificationUri(context!!.contentResolver, uri)
            }
            c
        }
    }

    override fun getType(uri: Uri): String? = null

    override fun insert(uri: Uri, contentValues: ContentValues?) = db?.let { db ->
        val dao = db.contactDao()
        val mValues = Gson().fromJson(Gson().toJson(contentValues), BaseEntity::class.java).mValues
        val id: Long = when (sUriMatcher.match(uri)) {
            CONTACT_DIR -> {
                val info = Gson().fromJson(mValues, ContactInfo::class.java)
                dao.insert(info)
            }
            else -> -1
        }
        val result = ContentUris.withAppendedId(uri, id)
        context!!.contentResolver.notifyChange(result, null)
        result
    }

    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?) =
        db?.let { db ->
            when (sUriMatcher.match(uri)) {
                CONTACT_ITEM -> {
                    val dao = db.contactDao()
                    val id = ContentUris.parseId(uri)
                    val result = dao.delete(dao.queryById(id))
                    context!!.contentResolver.notifyChange(
                        ContentUris.withAppendedId(uri, id),
                        null
                    )
                    result
                }
                else -> 0
            }
        } ?: 0

    override fun update(
        uri: Uri,
        contentValues: ContentValues?,
        selection: String?,
        selectionArgs: Array<String>?
    ) = db?.let { db ->
        when (sUriMatcher.match(uri)) {
            CONTACT_ITEM -> {
                val dao = db.contactDao()
                val mValues =
                    Gson().fromJson(Gson().toJson(contentValues), BaseEntity::class.java).mValues
                val info = Gson().fromJson(mValues, ContactInfo::class.java)
                val id = ContentUris.parseId(uri)
                val infoFin = dao.queryById(id)
                infoFin.merge(info)
                val result = dao.update(infoFin)
                context!!.contentResolver.notifyChange(ContentUris.withAppendedId(uri, id), null)
                result
            }
            CONTACT_MULTI -> {
                val dao = db.contactDao()
                val keyList = contentValues!!.keySet().toList()
                for (i in keyList.indices) {
                    when (contentValues.getAsString(keyList[i])) {
                        "insert" -> {
                            val info = Gson().fromJson(keyList[i], ContactInfo::class.java)
                            dao.insert(info)
                        }
                        "update" -> {
                            val info = Gson().fromJson(keyList[i], ContactInfo::class.java)
                            dao.update(info)
                        }
                        "delete" -> {
                            dao.delete(ContactInfo(keyList[i].toLong()))
                        }
                    }
                }
                context!!.contentResolver.notifyChange(CONTACT_TABLE_URI, null)
                keyList.size
            }
            else -> 0
        }
    } ?: 0
}