package com.base.appzxhy.ui.recovery

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import android.view.LayoutInflater
import android.view.View
import androidx.activity.SystemBarStyle
import androidx.activity.addCallback
import androidx.activity.enableEdgeToEdge
import androidx.core.app.ActivityCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.base.appzxhy.R
import com.base.appzxhy.base.BaseActivity
import com.base.appzxhy.bean.recovery.FolderBean
import com.base.appzxhy.bean.recovery.RecoveryBean
import com.base.appzxhy.bean.recovery.RecoveryBean.Companion.setAudioType
import com.base.appzxhy.bean.recovery.RecoveryBean.Companion.setDocumentType
import com.base.appzxhy.business.ads.AdsMgr
import com.base.appzxhy.business.ads.AdsShowCallBack
import com.base.appzxhy.databinding.ActivityFileScanResultBinding
import com.base.appzxhy.databinding.DialogExitFunctionBinding
import com.base.appzxhy.databinding.DialogPermissonOpenBinding
import com.base.appzxhy.utils.ActivityLauncher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch
import java.io.File
import java.util.LinkedList
import androidx.core.net.toUri
import androidx.core.graphics.drawable.toDrawable

class FileScanResultActivity : BaseActivity<ActivityFileScanResultBinding>(ActivityFileScanResultBinding::inflate) {

    private var scanOnce: Boolean = false
    private var scanType = 0

    private lateinit var fileFolderAdapter: FileFolderAdapter

    override fun useDefaultImmersive() {
        super.useDefaultImmersive()
    }

    @SuppressLint("SetTextI18n")
    override fun initView() {
        super.initView()
        scanType = intent.extras?.getInt("ScanType") ?: 0

//        LogEx.logDebug(TAG, "scanType=$scanType")
        when (scanType) {
            SCAN_PHOTOS -> {
                binding.tvTittle.text = "Photo Recovery"
                binding.tvFileType.text = "Photos"
            }

            SCAN_DOCUMENTS -> {
                binding.tvTittle.text = "Document Recovery"
                binding.tvFileType.text = "Documents"
            }

            SCAN_VIDEOS -> {
                binding.tvTittle.text = "Video Recovery"
                binding.tvFileType.text = "Videos"
            }

            SCAN_AUDIOS -> {
                binding.tvTittle.text = "Audio Recovery"
                binding.tvFileType.text = "Audios"
            }
        }
        fileFolderAdapter = FileFolderAdapter(scanType) { folderBean ->
            FileRecoveryActivity.folderBean = null
            FileRecoveryActivity.folderBean = folderBean
            startActivity(Intent(this, FileRecoveryActivity::class.java).apply {
                putExtra("ScanType", scanType)
            })
        }
        binding.rv.adapter = fileFolderAdapter

        if (checkStorePermission()) {
            beginScan()
        } else {
            showGerPermission(
                desc = "In order to scan and recover your lost photos, videos, and documents, we need to access your device storage. This permission is essential for our app to locate and restore your files.",
                deny = {
                },
                allow = {
                    requestStorePermission(launcher, result = {
                        if (it) beginScan() else finishToMainTop()
                    })
                })
        }
    }

    override fun initListener() {
        binding.flFanhui.setOnClickListener {
            onBackPressedDispatcher.onBackPressed()
        }
        onBackPressedDispatcher.addCallback {
            showExitFunctionDialog(this@FileScanResultActivity) {
                if (it) {
                    AdsMgr.showInsert(this@FileScanResultActivity, showCallBack = object : AdsShowCallBack() {
                        override fun next() {
                            finishToMainTop()
                        }
                    })
                }
            }
        }
    }

    fun Context.checkStorePermission(): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            Environment.isExternalStorageManager()
        } else {
            val readPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
            val writePermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
            return readPermission == PackageManager.PERMISSION_GRANTED && writePermission == PackageManager.PERMISSION_GRANTED;
        }
    }

    fun CoroutineScope.loadFileByFilter(
        flow1: MutableSharedFlow<String>? = null,
        flow2: MutableSharedFlow<Pair<Int, String>>? = null,
        folder: File,
        filter: (file: File) -> Boolean,
        onDo: ((file: File) -> Unit)? = null,
        onFinish: (() -> Unit)? = null
    ) = launch(Dispatchers.IO) {
        delay(1000)
        var size = 0

        //添加第一层文件到链表
        val linkList = LinkedList<File>()
        val fileList = folder.listFiles()
        fileList?.forEach {
            if (it.isDirectory) {
                linkList.add(it)
            } else {
                val flag = filter(it)
                if (flag) {
                    onDo?.invoke(it)
                    size++
                    flow2?.emit(Pair(size, it.absolutePath))
                }
                flow1?.emit(it.absolutePath)
            }
        }

        //链表取文件
        var tempFile: File
        while (!linkList.isEmpty()) {
            tempFile = linkList.removeFirst()
            val tempFileList = tempFile.listFiles()
            tempFileList?.forEach {
                if (it.isDirectory) {
                    linkList.add(it)
                } else {
                    val flag = filter(it)
//                    LogEx.logDebug(TAG, "$it flag=$flag")
                    if (flag) {
                        onDo?.invoke(it)
                        size++
                        flow2?.emit(Pair(size, it.absolutePath))
                    }
                    flow1?.emit(it.absolutePath)
                }
            }
        }
        onFinish?.invoke()
    }

    @SuppressLint("SetTextI18n")
    private fun beginScan() {
        if (scanOnce)
            return

        scanOnce = true
        //变量路径
        val mPathFlow = MutableSharedFlow<String>(
            replay = 5,//当新的订阅者Collect时，发送几个已经发送过的数据给它
            extraBufferCapacity = 5,//减去replay，MutableSharedFlow还缓存多少数据,缓冲池容量 = replay + extraBufferCapacity
            onBufferOverflow = BufferOverflow.DROP_OLDEST//缓存策略，三种 丢掉最新值、丢掉最旧值和挂起
        )
        val pathFlow: SharedFlow<String> = mPathFlow

        //符合条件Flow
        val mFoundFlow = MutableSharedFlow<Pair<Int, String>>(
            replay = 5,
            extraBufferCapacity = 5,
            onBufferOverflow = BufferOverflow.SUSPEND
        )
        val foundFlow: SharedFlow<Pair<Int, String>> = mFoundFlow


        val dialogClass = FileScanDialog(this)
        val scanDialog = dialogClass.showFileScanDialog(pathFlow, foundFlow) {

            pathList.add(it)
            binding.tvFileNumber.text = pathList.size.toString()
            setAdapterData(it)
        }

        val filter = when (scanType) {
            SCAN_PHOTOS -> FileHexEx::isImage
            SCAN_DOCUMENTS -> FileHexEx::isDocument
            SCAN_VIDEOS -> FileHexEx::isVideo
            SCAN_AUDIOS -> FileHexEx::isAudio
            else -> FileHexEx::isImage
        }
        val root = Environment.getExternalStorageDirectory()
        lifecycleScope.loadFileByFilter(
            mPathFlow,
            mFoundFlow,
            root, filter = filter,
            onDo = { file ->
//                LogEx.logDebug(TAG, "file =${file.absolutePath}")
            },
            onFinish = {
                lifecycleScope.launch(Dispatchers.Main) {
                    binding.ivWancheng.visibility = View.VISIBLE
                    binding.tvScanning.text = "Completed"
                    lifecycleScope.launchWhenResumed {
                        AdsMgr.showInsert(this@FileScanResultActivity)
                    }
                    binding.flEmpty.isVisible = pathList.isEmpty()
                    setAdapterData(null)
                    dialogClass.finishScan {
                        scanDialog.dismiss()
                    }
                }
            }
        )
    }

    private val pathList = ArrayList<String>()
    private val hashMap = HashMap<String, ArrayList<RecoveryBean>>()
    private fun setAdapterData(path: String? = null) {
        val flag = path?.let { addMapFolder(it) } ?: true
        if (flag) {
            binding.tvFolderNumber.text = hashMap.keys.size.toString()
            val mapList = hashMap.map {
                FolderBean(it.key, recoveryList = it.value)
            }
            fileFolderAdapter.setData(mapList)
        }
    }

    private fun addMapFolder(path: String): Boolean {
        var isNewFolder = false
        val folder = File(path).parent?.split("/")?.last() ?: ""
        if (hashMap[folder] == null) {
            hashMap[folder] = arrayListOf()
            isNewFolder = true
        }
        val recoveryBean = RecoveryBean(path)
        if (scanType == SCAN_DOCUMENTS) {
            recoveryBean.setDocumentType()
        }
        if (scanType == SCAN_AUDIOS) {
            recoveryBean.setAudioType()
        }
        hashMap[folder]?.add(recoveryBean)
        return isNewFolder
    }

    companion object {
        const val SCAN_PHOTOS = 1
        const val SCAN_DOCUMENTS = 2
        const val SCAN_VIDEOS = 3
        const val SCAN_AUDIOS = 4
    }

    @SuppressLint("SetTextI18n")
    fun Context.showGerPermission(
        tittle: String? = null,
        desc: String? = null,
        denyText: String? = null,
        allowText: String? = null,
        deny: ((view: Dialog) -> Unit)? = null,
        allow: ((view: Dialog) -> Unit)? = null
    ): Dialog {
        val dialog = Dialog(this)
        val binding = DialogPermissonOpenBinding.inflate(LayoutInflater.from(this))
        dialog.requestWindowFeature(1)
        dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        dialog.window!!.setLayout(-1, -1)
        dialog.setCanceledOnTouchOutside(false)
        dialog.setCancelable(false)
        dialog.setContentView(binding.root)

        tittle?.let { binding.tvTitle.text = it }
        desc?.let { binding.tvDesc.text = it }
        denyText?.let { binding.idDeny.text = it }
        allowText?.let { binding.idTvAllow.text = it }

        binding.idFullLottie.imageAssetsFolder = "recovery_permission_finger/images/"
        binding.idFullLottie.setAnimation("recovery_permission_finger/data.json")
        binding.idFullLottie.playAnimation()
        binding.idDeny.setOnClickListener {
            dialog.dismiss()
            deny?.invoke(dialog)
        }
        binding.idTvAllow.setOnClickListener {
            dialog.dismiss()
            allow?.invoke(dialog)
        }
        dialog.show()
        return dialog
    }


    @SuppressLint("UseKtx")
    fun Context.requestStorePermission(
        launcher: ActivityLauncher,
        jumpAction: (() -> Unit)? = null,
        result: (flag: Boolean) -> Unit
    ) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            val intent =
                Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
            intent.addCategory("android.intent.category.DEFAULT")
            intent.data = "package:${packageName}".toUri()
            jumpAction?.invoke()
            launcher.launch(intent) {
                result.invoke(checkStorePermission())
            }
        } else {
            launcher.launch(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { map ->
                result(map.values.all { it })
            }
        }

    }

    fun Context.showExitFunctionDialog(
        activity: Activity,
        exitAction: (showAd: Boolean) -> Unit
    ) {

        val dialog = Dialog(this)
        val binding = DialogExitFunctionBinding.inflate(LayoutInflater.from(this))
        dialog.requestWindowFeature(1)
        dialog.window?.setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
        dialog.window?.setLayout(-1, -1)
        dialog.setContentView(binding.root)
        dialog.show()

//        dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
//        val params = dialog.window?.attributes
//        params?.width = resources.getDimensionPixelOffset(R.dimen.dp_345)
//        dialog.window?.attributes = params
        AdsMgr.showNative(binding.flAd, R.layout.layout_admob_native_custom)
        binding.tvN.setOnClickListener {
            dialog.dismiss()
            exitAction.invoke(true)
        }
        binding.tvY.setOnClickListener {
            dialog.dismiss()
        }
    }


}