/*
 * Lunar Launcher
 * Copyright (C) 2022 Md Rasel Hossain
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package rasel.lunar.launcher.home

import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context.AUDIO_SERVICE
import android.content.DialogInterface
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.graphics.Bitmap
import android.media.AudioManager
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.provider.AlarmClock
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.EditText
import android.widget.RadioButton
import android.widget.TableRow
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.biometric.BiometricPrompt
import androidx.core.view.children
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import io.realm.kotlin.ext.query
import io.realm.kotlin.notifications.InitialResults
import io.realm.kotlin.notifications.ResultsChange
import io.realm.kotlin.notifications.UpdatedResults
import io.realm.kotlin.query.RealmResults
import io.realm.kotlin.query.Sort
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import okhttp3.ConnectionPool
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody
import org.json.JSONArray
import org.json.JSONObject
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R
import rasel.lunar.launcher.databinding.LauncherHomeBinding
import rasel.lunar.launcher.helpers.Constants.Companion.BOTTOM_SHEET_TAG
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_LOCK_METHOD
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_TODO_LOCK
import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_SETTINGS
import rasel.lunar.launcher.helpers.UniUtils.Companion.biometricPromptInfo
import rasel.lunar.launcher.helpers.UniUtils.Companion.canAuthenticate
import rasel.lunar.launcher.helpers.UniUtils.Companion.expandNotificationPanel
import rasel.lunar.launcher.helpers.UniUtils.Companion.lockMethod
import rasel.lunar.launcher.home.adapters.NotificationItemAdapter
import rasel.lunar.launcher.home.adapters.RecentCallsAdapter
import rasel.lunar.launcher.home.adapters.RssItemAdapter
import rasel.lunar.launcher.home.adapters.SmsLogsAdapter
import rasel.lunar.launcher.model.CurrentPlayItem
import rasel.lunar.launcher.model.NotificationItem
import rasel.lunar.launcher.model.RssData
import rasel.lunar.launcher.model.RssDataInterface
import rasel.lunar.launcher.model.RssDataType
import rasel.lunar.launcher.qaccess.QuickAccess
import rasel.lunar.launcher.settings.SettingsActivity
import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.BitmapConverter
import rasel.lunar.launcher.utils.JamoUtils
import rasel.lunar.launcher.utils.SimpleFingerGestures
import rasel.lunar.launcher.utils.beforeDay
import rasel.lunar.launcher.view.TableRadioGroup
import rasel.lunar.launcher.workers.RecentCall
import rasel.lunar.launcher.workers.RecentSms
import rasel.lunar.launcher.workers.TelegramBotGetter
import rasel.lunar.launcher.workers.WorkersDb
import java.net.URLEncoder
import java.util.Calendar
import java.util.Date
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern


internal class LauncherHome : Fragment() {

    lateinit var binding: LauncherHomeBinding
    private lateinit var fragManager: FragmentManager
    private lateinit var settingsPrefs: SharedPreferences
    private lateinit var batteryReceiver: BatteryReceiver
    private var shouldResume = true

    companion object {
        var home : LauncherHome? = null
        var lastedFinishedPageUrl : String = ""
        //        var recentCalls = arrayListOf<RecentCall>()
//        var callList = arrayListOf<RecentCall>()
//        var smsList = arrayListOf<RecentSms>()
        var listTags = arrayListOf<RssDataInterface>()
    }

//    private var nReceiver: NotificationReceiver? = null
//
//    class NotificationReceiver : BroadcastReceiver() {
//        override fun onReceive(context: Context?, intent: Intent) {
//            BLog.LOGE("NotificationReceiver >>>> ${intent.extras?.keySet()}")
//        }
//    }

    val UPDATE_DELAY = 1000L
    val commandHandler = Handler(Looper.getMainLooper())

    val smsUpdate = Runnable {

        chooseAdpater()
    }

    val callUpdate = Runnable {

        chooseAdpater()
    }

    val infoUpdate = Runnable {
        chooseAdpater()
    }

    val notiUpdate = Runnable {
        chooseAdpater()
    }


    var lasted : List<RssData>? = null
    var lastedNoti : List<NotificationItem>? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        home = this
        BLog.LOGE("${this} ::::: onCreate >>>> ")
    }
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        BLog.LOGE("${this} ::::: onCreateView >>>> ")
        binding = LauncherHomeBinding.inflate(inflater, container, false)
        fragManager = lActivity!!.supportFragmentManager
        settingsPrefs = requireContext().getSharedPreferences(PREFS_SETTINGS, 0)
        batteryReceiver = BatteryReceiver(binding.batteryProgress)
        mRecentCallsAdapter  = RecentCallsAdapter(arrayListOf(), requireContext())
        mSmsLogsAdapter  = SmsLogsAdapter(arrayListOf(), requireContext())
        mNotiAdapter = NotificationItemAdapter(requireContext())
        mRssAdapter = RssItemAdapter(requireContext())

        val decoration = DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL)

        binding.notiList.addItemDecoration(decoration)
        binding.infoList.addItemDecoration(decoration)

        binding.smsList.visibility = View.GONE
        binding.infoList.visibility = View.GONE

        binding.notiList.layoutManager = LinearLayoutManager(requireContext())
        binding.mainList.layoutManager = GridLayoutManager(requireContext(),2)
        binding.smsList.layoutManager = GridLayoutManager(requireContext(),2)
        binding.infoList.layoutManager = LinearLayoutManager(requireContext())

        binding.mainList.adapter = mRecentCallsAdapter
        binding.smsList.adapter = mSmsLogsAdapter
        binding.infoList.adapter = mRssAdapter
        binding.notiList.adapter = mNotiAdapter

        binding.favAppsGroup.setOnClickListener { searchData() }

        try{binding.mainList.removeOnScrollListener(onScrChanged)}catch (e : Exception){e.printStackTrace()}
        binding.mainList.addOnScrollListener(onScrChanged)
        try{binding.smsList.removeOnScrollListener(onScrChanged)}catch (e : Exception){e.printStackTrace()}
        binding.smsList.addOnScrollListener(onScrChanged)
        try{binding.infoList.removeOnScrollListener(onScrChanged)}catch (e : Exception){e.printStackTrace()}
        binding.infoList.addOnScrollListener(onScrChanged)
        try{binding.notiList.removeOnScrollListener(onScrChanged)}catch (e : Exception){e.printStackTrace()}
        binding.notiList.addOnScrollListener(onScrChanged)

        binding.currentMusic?.setOnClickListener {
            lActivity?.apply {
                packageManager?.apply {
                    startActivity(getLaunchIntentForPackage("com.google.android.apps.youtube.music"))
                }
            }
        }

        GlobalScope.launch {
            WorkersDb.getRealm().apply {
                query<CurrentPlayItem>().find().asFlow().collect { changes: ResultsChange<CurrentPlayItem> ->
                    binding.currentMusic?.postDelayed({
                        if (changes.list.size > 0) {
                            changes.list?.first()?.let {
                                binding.currentMusic.visibility = View.VISIBLE
                                binding.nextPlay.visibility = View.GONE
                                binding.artist.text = it.artists
                                binding.title.text = it.title


                                var bitmap: Bitmap? = null
                                try {
                                    bitmap = BitmapConverter.StringToBitmap(it.albumArt)
                                    binding.albumArt.setImageBitmap(bitmap)
                                } catch (exception: java.lang.Exception) {
                                    // log error
                                }
                            }
                        } else {
                            binding.currentMusic.visibility = View.GONE
                            binding.nextPlay.visibility = View.VISIBLE
                        }}, 150L)
                }
            }
        }

//        BLog.LOGE("onCreateView()")
        binding.nextBtn.setOnClickListener {
            val mAudioManager =
                requireContext().getSystemService(AUDIO_SERVICE) as AudioManager

            val eventtime: Long = SystemClock.uptimeMillis()

            val downEvent =
                KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT, 0)
            mAudioManager.dispatchMediaKeyEvent(downEvent)

            val upEvent =
                KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT, 0)
            mAudioManager.dispatchMediaKeyEvent(upEvent)
        }
        binding.nextPlay.setOnClickListener {
            val mAudioManager =
                requireContext().getSystemService(AUDIO_SERVICE) as AudioManager

            val eventtime: Long = SystemClock.uptimeMillis()

            val downEvent =
                KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY, 0)
            mAudioManager.dispatchMediaKeyEvent(downEvent)

            val upEvent =
                KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY, 0)
            mAudioManager.dispatchMediaKeyEvent(upEvent)
        }


        queryInfos()
        queryNotice()
        return binding.root
    }

    val hideListViewTime = 1000L * 60L * 15L
    val hideListView  = {

        binding.notiList.visibility = View.GONE
        binding.mainList.visibility = View.GONE
        binding.infoList.visibility = View.GONE
        binding.smsList.visibility = View.GONE
        binding.otherCheck.isSelected = false
        binding.recentSms.isSelected = false
        binding.missedCalls.isSelected = false
        binding.notice.isSelected = false
    }


    val onScrChanged = object : RecyclerView.OnScrollListener() {
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            super.onScrollStateChanged(recyclerView, newState)
            commandHandler.removeCallbacks(hideListView)
            when (newState) {
                RecyclerView.SCROLL_STATE_IDLE -> {
                    commandHandler.postDelayed(hideListView, hideListViewTime)
                }
                RecyclerView.SCROLL_STATE_DRAGGING -> {
                }
                RecyclerView.SCROLL_STATE_SETTLING -> {
                }
            }
        }

        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)
            commandHandler.removeCallbacks(hideListView)
        }
    }

    private fun queryNotice() {
        var mWorkManager = WorkManager.getInstance(requireContext())
        Executors.newSingleThreadScheduledExecutor().schedule({
            mWorkManager.enqueue(OneTimeWorkRequest.from(TelegramBotGetter::class.java))
        }, 5, TimeUnit.SECONDS)
        try { noticeJob?.cancel() } catch (e:Exception) {e.printStackTrace()}
        mNotificationResult = null
        try {
            System.gc()
        }catch (e : Exception){
            e.printStackTrace()
        }

        mNotificationResult = WorkersDb.getRealm().query<NotificationItem>().sort("postTime",Sort.DESCENDING).find()
        noticeJob = CoroutineScope(Dispatchers.Default).launch {
            mNotificationResult?.asFlow()?.collect { changes: ResultsChange<NotificationItem> ->
                commandHandler.removeCallbacks(hideListView)
                when (changes) {
                    is UpdatedResults -> {
//                        BLog.LOGE("ResultsChange onNotificationPosted")
                        WorkersDb.getRealm().apply {
                            lastedNoti = copyFromRealm(changes.list)
                        }
                        commandHandler.removeCallbacks(notiUpdate)
                        commandHandler.postDelayed(notiUpdate, UPDATE_DELAY)
                    }

                    else -> {
                        // types other than UpdatedResults are not changes -- ignore them
                    }
                }
            }
        }
        noticeJob?.start()
    }

    fun queryInfos(filter: Collection<RssDataType>? = arrayListOf(RssDataType.GURU,RssDataType.Most,RssDataType.REDDIT_nsfw)) {
        try { infosJob?.cancel() } catch (e:Exception) {e.printStackTrace()}
        mRssDataResult = null
        try {
            System.gc()
        }catch (e : Exception){e.printStackTrace()}

        WorkersDb.getRealm().apply { writeBlocking {
            delete(query<RssData>().query("pubDate < $0",beforeDay(Date(),3)).query("category != $0 || category != $1 ", RssDataType.GURU.name,RssDataType.Most.name).find())
        }}
        var rQ = WorkersDb.getRealm().query<RssData>().query("pubDate > $0", beforeDay(Date(),3))
        filter!!.forEach {
            rQ = rQ.query("category != $0", it.name)
        }
        //limit(1000)
        mRssDataResult = rQ.sort("pubDate ", Sort.DESCENDING).find()
//        BLog.LOGE("${this} ::::: queryInfos after query find >>>> ")
        infosJob = CoroutineScope(Dispatchers.Default).launch {
            mRssDataResult?.asFlow()?.collect { changes: ResultsChange<RssData> ->
                commandHandler.removeCallbacks(hideListView)
                commandHandler.removeCallbacks(infoUpdate)
                when (changes) {
                    is InitialResults -> {
//                        BLog.LOGE("${this} ::::: queryInfos after changes size >>>> ${changes.list.size}")
                        WorkersDb.getRealm().apply {
                            lasted = copyFromRealm(changes.list)
                        }
                        commandHandler.postDelayed(infoUpdate, UPDATE_DELAY)
                    }
                    is UpdatedResults -> {
//                        lasted = changes.list
//                        commandHandler.postDelayed(infoUpdate, UPDATE_DELAY * 3)
                    }
                    else -> {
                    }
                }
            }
        }
        infosJob?.start()
    }

    fun queryInfos(keyword : String, category : ArrayList<String> = arrayListOf()) {
        try { infosJob?.cancel() } catch (e:Exception) {e.printStackTrace()}
        mRssDataResult = null
        try {
            System.gc()
        }catch (e : Exception){e.printStackTrace()}

        WorkersDb.getRealm().apply { writeBlocking {
            delete(query<RssData>().query("pubDate < $0",beforeDay(Date(),3)).query("category != $0 || category != $1 ", RssDataType.GURU.name,RssDataType.Most.name).find())
        }}
        var rQ = WorkersDb.getRealm().query<RssData>().query("pubDate > $0", beforeDay(Date(),3))
        if(keyword.length > 0) {
            BLog.LOGE("queryInfos it >>> ${keyword}")
            if (JamoUtils.CHOSUNG.contains(keyword.split("")[0])) {
                rQ = rQ.query(
                    "title CONTAINS $0 OR chosung CONTAINS $1 ",
                    keyword,
                    keyword
                )
            } else if(Pattern.matches("^[가-힣]*\$", keyword)){
                rQ = rQ.query(
                    "title CONTAINS $0",
                    keyword
                )
            }else {

                rQ = rQ.query(
                    "title CONTAINS $0 OR  title CONTAINS $1",
                    keyword.toUpperCase(),
                    keyword.toLowerCase()
                )
            }
        }
        var queryString = ""
        if (category.size > 0) {
            category.forEachIndexed { idx, it ->
                if (idx == 0) {
                    queryString = queryString.plus("category == '${it}'")
                } else {
                    queryString = queryString.plus(" OR category == '${it}' ")
                }
            }

            rQ = rQ.query(queryString)
        }

        mRssDataResult = rQ.sort("pubDate ", Sort.DESCENDING).find()
        infosJob = CoroutineScope(Dispatchers.Default).launch {
            mRssDataResult?.asFlow()?.collect { changes: ResultsChange<RssData> ->
                commandHandler.removeCallbacks(hideListView)
                commandHandler.removeCallbacks(infoUpdate)
                when (changes) {
                    is InitialResults -> {
                        WorkersDb.getRealm().apply {
                            lasted = copyFromRealm(changes.list)
                        }

                        commandHandler.postDelayed(infoUpdate, UPDATE_DELAY)
                    }
                    is UpdatedResults -> {
//                        lasted = changes.list
//                        commandHandler.postDelayed(infoUpdate, UPDATE_DELAY * 3)
                    }
                    else -> {
                    }
                }
            }
        }
        infosJob?.start()
    }

    var infosJob : Job? = null
    var noticeJob : Job? = null

    lateinit var mRecentCallsAdapter : RecentCallsAdapter
    lateinit var mSmsLogsAdapter : SmsLogsAdapter
    lateinit var mRssAdapter : RssItemAdapter
    lateinit var mNotiAdapter : NotificationItemAdapter
    var mRssDataResult : RealmResults<RssData>? = null
    var mNotificationResult : RealmResults<NotificationItem>? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        BLog.LOGE("${this} ::::: onViewCreated >>>> ")

        rootViewGestures()
        batteryProgressGestures()
        todosGestures()

        BLog.LOGE("onViewCreated()")
//        mWorkManager.
        /* refresh the to-do list after getting back from TodoManager */
        fragManager.addOnBackStackChangedListener {
            BLog.LOGE("addOnBackStackChangedListener()")
            shouldResume = if (fragManager.backStackEntryCount == 0) {
                binding.root.visibility = View.VISIBLE
                true
            } else {
                binding.root.visibility = View.GONE
                false
            }
        }

        var checkListner  = object : View.OnClickListener {
            override fun onClick(v: View?) {
                commandHandler.removeCallbacks(hideListView)
                var views = arrayListOf(binding.mainList, binding.smsList, binding.infoList, binding.notiList)
                var chechboxs = arrayListOf(binding.missedCalls,
                    binding.recentSms,
                    binding.otherCheck,
                    binding.notice)
                chechboxs.remove(v)
                when (v) {
                    binding.missedCalls -> {
                        if (binding.missedCalls.isSelected ) {
                            binding.missedCalls.isSelected = false

                        } else {
                            binding.missedCalls.isSelected = true
                            views.remove(binding.mainList)
                            binding.mainList.visibility = View.VISIBLE
                        }
                    }
                    binding.recentSms -> {
                        if (binding.recentSms.isSelected ) {
                            binding.recentSms.isSelected = false

                        } else {
                            binding.recentSms.isSelected = true
                            views.remove(binding.smsList)
                            binding.smsList.visibility = View.VISIBLE
                        }
                    }
                    binding.otherCheck -> {
                        if (binding.otherCheck.isSelected ) {
                            binding.otherCheck.isSelected = false

                        } else {
                            queryInfos()
                            binding.otherCheck.isSelected = true
                            views.remove(binding.infoList)
                            binding.infoList.scrollToPosition(0)
                            binding.infoList.visibility = View.VISIBLE
                        }
                    }
                    binding.notice -> {
                        if (binding.notice.isSelected ) {
                            binding.notice.isSelected = false
                        } else {
                            queryNotice()
                            binding.notice.isSelected = true
                            views.remove(binding.notiList)
                            binding.notiList.visibility = View.VISIBLE
                        }
                    }
                }
                chechboxs.forEach { it.isSelected = false }
                views.forEach { it.visibility = View.GONE }
                chooseAdpater()
            }
        }

        binding.otherCheck.setOnClickListener(checkListner)
        binding.recentSms.setOnClickListener(checkListner)
        binding.missedCalls.setOnClickListener(checkListner)
        binding.notice.setOnClickListener(checkListner)
        binding.otherCheck.setOnLongClickListener {
            queryInfos()
            true
        }

    }
//    https://www.youtube.com/results?search_query=sds


    fun searchData() {
        val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
        builder.setTitle("Command Line")
        val viewInflated: View = LayoutInflater.from(context)
            .inflate(R.layout.search_layout, view as ViewGroup?, false)
        val input = viewInflated.findViewById<View>(R.id.input) as EditText
        val categoryz = viewInflated.findViewById<TableRadioGroup>(R.id.categoryz) as TableRadioGroup
        categoryz.setMaxColumns(5)
        categoryz.setMaxRows(5)
        categoryz.setOnCheckedChangeListener(object : TableRadioGroup.OnCheckedChangeListener {
            override fun onCheckedChanged(group: TableRadioGroup?, checkedId: Int) {

            }
        })
        var idx = 0
        RssDataType.values().reversed().toList().chunked(5).forEach {
            var tb = TableRow(requireContext())
            it.forEach { c ->
                if(c.equals(RssDataType.NO_DATA) == false) {
                    tb.addView(
                        CheckBox(requireContext()).apply {
                            this.tag = c.name
                            this.text = c.name
                        }
                    )
                }
            }
            categoryz.addView(tb)
        }

        builder.setView(viewInflated)
        builder.setPositiveButton(android.R.string.ok,
            DialogInterface.OnClickListener { dialog, which ->
                dialog.dismiss()
                var  category = arrayListOf<String>()
                categoryz.children.forEach {
                    if(it is TableRow) {
                        it.children.forEach {
                            if (it is CheckBox && it.isChecked) {
                                (it.tag as? String)?.let { category.add(it) }
                            }
                        }
                    }
                }
                queryInfos(keyword =input.text.toString(),category)
            })
        builder.setNegativeButton(android.R.string.cancel,
            DialogInterface.OnClickListener { dialog, which -> dialog.cancel() })
        builder.show()
    }



    fun showAl() {
        binding.alcholKatalkT.visibility = View.VISIBLE
        binding.alcholKatalkT.setOnClickListener {
            openSearchApps("kakaot://taxi?dest_lat=${URLEncoder.encode("37.467696")}&dest_lng=${URLEncoder.encode("127.101063")}","com.kakao.taxi")
        }

    }
    fun openSearchApps(schemeString : String, pakage : String? = null) {
        val gmmIntentUri = Uri.parse(schemeString)
        val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
        pakage?.let {
            mapIntent.setPackage(pakage)
        }
        startActivity(mapIntent)
    }
    fun hideAl() {
        binding.alcholKatalkT.visibility = View.GONE
        binding.alcholKatalkT.setOnClickListener {

        }
    }

    fun chooseAdpater () {
        commandHandler.removeCallbacks(hideListView)
        binding.mainList.visibility = View.INVISIBLE
        binding.smsList.visibility = View.INVISIBLE
        binding.infoList.visibility = View.INVISIBLE
        binding.notiList.visibility = View.INVISIBLE

        var dateParam = beforeDay(Date(),30).toString()
        if (binding.missedCalls.isSelected) {
            WorkersDb.getRealm().apply {
                val result = query<RecentCall>().query("callDayTime >= $0", dateParam).sort("callDayTime", Sort.DESCENDING).find()
                val list = copyFromRealm(result)
                binding.missedCalls.text = "최근 통화 [${list.size}]"
                binding.mainList.visibility = View.VISIBLE
                mRecentCallsAdapter.updateData(list)
                binding.recentSms.isSelected = false
                binding.otherCheck.isSelected = false
                binding.notice.isSelected = false
            }
        } else if(binding.recentSms.isSelected){
            WorkersDb.getRealm().apply {
                val result = query<RecentSms>().query("rcvDate >= $0 OR pstDate >= $0 ", dateParam)
                    .sort("rcvDate",Sort.DESCENDING).find()
                if (result.size > 0) {
                    try {
                        binding.recentSms.text = "최근 문자 [${result.size}]"
                        binding.smsList.visibility = View.VISIBLE
                        val list =  copyFromRealm(result)
                        mSmsLogsAdapter.updateData(list)
                        binding.missedCalls.isSelected = false
                        binding.otherCheck.isSelected = false
                        binding.notice.isSelected = false
                    } catch (e: Exception) {

                    }
                }
            }
        } else if(binding.otherCheck.isSelected) {
            binding.missedCalls.isSelected = false
            binding.recentSms.isSelected = false
            binding.notice.isSelected = false
            binding.infoList.visibility = View.VISIBLE
            binding.otherCheck.text = "최근 정보[${lasted?.size ?: "-"}]"
            lasted?.let { mRssAdapter.updateData(it) }
        }
        else if(binding.notice.isSelected) {
            binding.missedCalls.isSelected = false
            binding.recentSms.isSelected = false
            binding.otherCheck.isSelected = false
            binding.notiList.visibility = View.VISIBLE
            binding.notice.text = "알림 센터[${lastedNoti?.size ?: "-"}]"
            lastedNoti?.let { mNotiAdapter.updateData(it)}
        }
        commandHandler.postDelayed(hideListView, hideListViewTime)
    }
    override fun onResume() {
        super.onResume()
        BLog.LOGE("${this} ::::: onResume >>>> ")
        if (shouldResume) {

            /* register battery changes */
            requireContext().registerReceiver(batteryReceiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
            /* time and date */
//            binding.time.textLocale = Locale.US
//            binding.date.textLocale = Locale.US
//            if (DateFormat.is24HourFormat(requireContext())) {
//                binding.time.format24Hour = timeFormat
//                binding.date.format24Hour = "yyyy년 M월 W주차, dd일 E요일"
//            } else {
//                binding.time.format12Hour = timeFormat
//                binding.date.format12Hour = dateFormat
//            }
            /* show weather */
//            WeatherExecutor(settingsPrefs).generateWeatherString(binding.weather)
        }

    }







    override fun onPause() {
        super.onPause()
        /* unregister battery changes */
        if (shouldResume) requireContext().unregisterReceiver(batteryReceiver)
    }


    var mFingerGestureListener = object : SimpleFingerGestures.OnFingerGestureListener {
        override fun onSwipeUp(
            targetView: View,
            fingers: Int,
            gestureDuration: Long,
            gestureDistance: Double
        ): Boolean {
            when(fingers) {
                3 -> QuickAccess().show(fragManager, BOTTOM_SHEET_TAG)
                2->{
                    var startIntene = Intent(Intent.ACTION_MAIN)
                    startIntene.setComponent(ComponentName("com.mime.dualscreenview","com.mime.dualscreenview.activity.Intro"))
                    startActivity(startIntene)
                }
                else -> {}
            }
            return false
        }

        override fun onSwipeDown(
            targetView: View,
            fingers: Int,
            gestureDuration: Long,
            gestureDistance: Double
        ): Boolean {
            when(fingers) {
                2 ->
                    if (targetView?.equals(binding.batteryProgress) ?: false) {
                        expandNotificationPanel(requireContext())
                    } else {
                        expandNotificationPanel(requireContext())
                    }
                4->{
                    var startIntene = Intent(Intent.ACTION_MAIN)
                    startIntene.setComponent(ComponentName("com.samsung.android.app.interpreter","com.samsung.android.app.interpreter.interpretation.view.InterpretationActivity"))
                    startActivity(startIntene)
                }
                3-> {
                    lActivity!!.startActivity(Intent(requireContext(), SettingsActivity::class.java))
                }
                else -> {}
            }
            return false
        }

        override fun onSwipeLeft(
            targetView: View,
            fingers: Int,
            gestureDuration: Long,
            gestureDistance: Double
        ): Boolean {
            return false
        }

        override fun onSwipeRight(
            targetView: View,
            fingers: Int,
            gestureDuration: Long,
            gestureDistance: Double
        ): Boolean {
            return false
        }

        override fun onPinch(
            targetView: View,
            fingers: Int,
            gestureDuration: Long,
            gestureDistance: Double
        ): Boolean {
            return false
        }

        override fun onUnpinch(
            targetView: View,
            fingers: Int,
            gestureDuration: Long,
            gestureDistance: Double
        ): Boolean {
            return false
        }

        override fun onDoubleTap(targetView: View,fingers: Int): Boolean {

            when(fingers) {
                1 -> lockMethod(settingsPrefs.getInt(KEY_LOCK_METHOD, 0), requireContext(), binding.favAppsGroup)
                else -> {}
            }
            return false
        }

        override fun onLongPress(targetView: View,fingers: Int): Boolean {
            if (view?.equals(binding.batteryProgress) ?: false) {
                lActivity!!.startActivity(Intent(requireContext(), SettingsActivity::class.java))
            } else if  (view?.equals(binding.mainList) ?: false) {
                when (settingsPrefs.getBoolean(KEY_TODO_LOCK, false)) {
                    false -> launchTodoManager()
                    /* show authentication screen if lock is on */
                    true -> {
                        if (canAuthenticate(requireContext())) {
                            val biometricPrompt = BiometricPrompt(lActivity!!, authenticationCallback)
                            try {
                                biometricPrompt.authenticate(biometricPromptInfo(lActivity!!.getString(R.string.todo_manager)))
                            } catch (exception: Exception) {
                                exception.printStackTrace()
                            }
                        }
                    }
                }
            }
            return false
        }

        override fun onClick(targetView: View,fingers: Int): Boolean {
//            BLog.LOGE("onClick ${view} , fingers ${fingers}")
            when(fingers) {
                1 -> {
                    if (view?.equals(binding.batteryProgress) ?: false && fingers == 1) {
                        requireContext().startActivity(
                            Intent(AlarmClock.ACTION_SHOW_ALARMS).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        )
                    }
                }
                2-> {
                    lockMethod(settingsPrefs.getInt(KEY_LOCK_METHOD, 0), requireContext(), binding.favAppsGroup)
                }
                else -> {

                }
            }

            return false
        }

    }


    fun jsonObjLog(pkey : String ,key : String, jsonObject: JSONObject) {
        if (jsonObject?.has(key) == true && jsonObject?.get(key) is String) {
            BLog.LOGE("jsonObjLog $pkey String in $key >> ${jsonObject?.getString(key)}")
        }
        else if (jsonObject?.has(key) == true  && jsonObject?.get(key) is JSONObject) {
            var obj = jsonObject?.getJSONObject(key)
            BLog.LOGE("jsonObjLog $pkey JSONObject in $key >> ${obj}")
            obj?.keys()?.forEach {
//                jsonObjLog(key,it, obj)
            }
        }
        else if (jsonObject?.has(key) == true  && jsonObject?.get(key) is JSONArray) {
            BLog.LOGE("jsonObjLog $pkey JSONArray in $key >> ${jsonObject?.getJSONArray(key)}")
            var array = jsonObject?.getJSONArray(key)
            for ( i in 0..<(array?.length() ?: 0)) {
                if (array?.get(i) is String) {

                } else if (array?.get(i) is JSONObject) {
                    var child = array?.getJSONObject(i)
                    child?.keys()?.forEach {
//                        jsonObjLog(key, it, child)
                    }
                } else if (array?.get(i) is JSONArray) {
                    BLog.LOGE("jsonObjLog $pkey JSONArray in $key >> ${array?.getJSONArray(i)}")
                }
            }
        } else {
            BLog.LOGE("jsonObjLog $pkey else in $key >> ${if(jsonObject?.has(key) == true) (jsonObject?.get(key)) else ("")}")
        }
    }







    /* gestures on root view */
    @SuppressLint("ClickableViewAccessibility")
    private fun rootViewGestures() {
        binding.root.setOnTouchListener(SimpleFingerGestures(context = requireContext(), binding.root , mFingerGestureListener))
    }



    /* gestures on battery progress indicator area */
    @SuppressLint("ClickableViewAccessibility")
    private fun batteryProgressGestures() {
        binding.batteryProgress.setOnTouchListener(SimpleFingerGestures(context = requireContext(), binding.batteryProgress , mFingerGestureListener))
    }

    /* gestures on to-do area */
    @SuppressLint("ClickableViewAccessibility")
    private fun todosGestures() {
        binding.mainList.setOnTouchListener(SimpleFingerGestures(context = requireContext(), binding.mainList , mFingerGestureListener))
    }

    /* authentication callback for TodoManager lock */
    private val authenticationCallback = object : BiometricPrompt.AuthenticationCallback() {
        override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
            launchTodoManager()
        }
        override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
            Toast.makeText(requireContext(), lActivity!!.getString(R.string.authentication_error), Toast.LENGTH_SHORT).show()
        }
        override fun onAuthenticationFailed() {
            Toast.makeText(requireContext(), lActivity!!.getString(R.string.authentication_failed), Toast.LENGTH_SHORT).show()
        }
    }

    /* launch TodoManager fragment */
    private fun launchTodoManager() {
//        fragManager.beginTransaction().replace(R.id.mainFragmentsContainer, TodoManager())
//            .addToBackStack("").commit()
    }



    /* get time format string */
    private val timeFormat: String? get() {
//        when (settingsPrefs.getInt(KEY_TIME_FORMAT, 0)) {
//            0 -> return if (DateFormat.is24HourFormat(requireContext())) {
//                "kk:mm"
//            } else {
//                "HH:mm a"
//            }
//            1 -> return "HH:mm a"
//            2 -> return "kk:mm"
//        }
        return "a HH : mm"
    }

    /* get date number suffix */
    private val dateNumberSuffix: String get() {
        return when (Calendar.getInstance()[Calendar.DAY_OF_MONTH]) {
            1, 21, 31 -> "ˢᵗ"
            2, 22 -> "ⁿᵈ"
            3, 23 -> "ʳᵈ"
            else -> "ᵗʰ"
        }
    }

    /* get date format string */
    private val dateFormat: String get() {
//        settingsPrefs.getString(KEY_DATE_FORMAT, DEFAULT_DATE_FORMAT).let {
//            return if (it!!.contains("x")) {
//                it.replace("x", dateNumberSuffix)
//            } else {
//                it
//            }
//        }
        return "yyyy년 M월 W주차, dd일 E요일"
    }

}




