package com.adealink.weparty.commonui.mediapicker.imageselect

import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Build
import android.view.View
import androidx.activity.viewModels
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.adealink.frame.aab.util.getCompatString
import com.adealink.frame.base.Rlt
import com.adealink.frame.base.fastLazy
import com.adealink.frame.log.Log
import com.adealink.frame.mvvm.view.viewBinding
import com.adealink.frame.util.DisplayUtil
import com.adealink.frame.util.FileProvider7
import com.adealink.weparty.App
import com.adealink.weparty.R
import com.adealink.weparty.commonui.BaseActivity
import com.adealink.weparty.commonui.ext.gone
import com.adealink.weparty.commonui.ext.show
import com.adealink.weparty.commonui.mediapicker.imageselect.cache.videoCoverCache
import com.adealink.weparty.commonui.mediapicker.imageselect.clip.ClipImageLifecycleObserver
import com.adealink.weparty.commonui.mediapicker.imageselect.clip.ClipParamData
import com.adealink.weparty.commonui.mediapicker.imageselect.clip.avatarClipParam
import com.adealink.weparty.commonui.mediapicker.imageselect.listener.OnOperateListener
import com.adealink.weparty.commonui.mediapicker.imageselect.model.AddInfo
import com.adealink.weparty.commonui.mediapicker.imageselect.model.LoadMediaConfig
import com.adealink.weparty.commonui.mediapicker.imageselect.model.LocalMedia
import com.adealink.weparty.commonui.mediapicker.imageselect.model.LocalMediaFolder
import com.adealink.weparty.commonui.mediapicker.imageselect.model.MediaInfo
import com.adealink.weparty.commonui.mediapicker.imageselect.model.MediaType
import com.adealink.weparty.commonui.mediapicker.imageselect.selectpreview.SelectPreviewLifecycleObserver
import com.adealink.weparty.commonui.mediapicker.imageselect.selectpreview.SelectPreviewResult
import com.adealink.weparty.commonui.mediapicker.imageselect.takePhoto.TakePhotoLifecycleObserver
import com.adealink.weparty.commonui.mediapicker.imageselect.util.PictureMimeType
import com.adealink.weparty.commonui.mediapicker.imageselect.view.AddItemViewBinder
import com.adealink.weparty.commonui.mediapicker.imageselect.view.ImageFolderItemViewBinder
import com.adealink.weparty.commonui.mediapicker.imageselect.view.ImageItemViewBinder
import com.adealink.weparty.commonui.mediapicker.imageselect.viewmodel.MediaSelectViewModel
import com.adealink.weparty.commonui.recycleview.adapter.multitype.MultiTypeAdapter
import com.adealink.weparty.commonui.recycleview.itemdecoration.GridSpacingItemDecoration
import com.adealink.weparty.commonui.toast.util.showToast
import com.adealink.weparty.commonui.widget.CommonDialog
import com.adealink.weparty.databinding.ActivityImageSelectBinding
import com.adealink.weparty.hardware.Hardware
import com.adealink.weparty.permission.PermissionUtils
import com.adealink.weparty.storage.file.FilePath.clipImagePath
import com.adealink.weparty.storage.file.FilePath.takePhotoImagePath
import com.adealink.weparty.util.QMUIStatusBarHelper
import java.io.File

class ImageSelectActivity : BaseActivity(), OnOperateListener {

    companion object {
        const val TAG = "ImageSelectActivity"
        const val SPAN_COUNT = 3
        const val KEY_SOURCE = "source"
        const val KEY_MAX_NUM = "key_max_num"
        const val KEY_CLIP_PARAM_DATA = "key_clip_param_data"
        const val KEY_MEDIA_TYPE = "key_media_type"
        const val SELECT_IMAGE_PATH = "select_image_path"
        const val SELECT_IMAGE_URI = "select_image_uri"
        const val SELECT_IMAGES = "select_images"
        const val KEY_GIF_OPTION = "key_gif_option"
        const val SHOW_MES_TIP = "show_mes_tip"
        const val MESSAGE_GIF_MAX_SIZE_KB = 5 * 1024 * 1024 //GIF 图片上传最大size
        const val COVER_EXPIRE_TIME = "cover_expire_time"
        const val KEY_FROM_POSITION = "from_position"
        const val KEY_SELECTED_MEDIA_LIST = "selected_media_list"
        const val KEY_VIDEO_MAX_SECOND = "video_max_second"
        const val KEY_IMAGE_MIN_SIZE = "image_min_size" //图片最小尺寸，默认800px
        const val MIN_IMAGE_AVATAR_SIZE = 800 //图片最小尺寸，默认800px
        const val MIN_IMAGE_NORMAL_SIZE = 400 //常规的图片最小尺寸，默认400px
        const val TOP_TIPS_STRING = "top_tips_string" //顶部提示文字

    }

    private val binding by viewBinding(ActivityImageSelectBinding::inflate)
    private val mediaSelectViewModel by viewModels<MediaSelectViewModel>()
    private lateinit var imageFolderListAdapter: MultiTypeAdapter
    private lateinit var selectImageListAdapter: MultiTypeAdapter
    private lateinit var gridLayoutManager: GridLayoutManager
    private lateinit var clipImageObserver: ClipImageLifecycleObserver
    private lateinit var takePhotoObserver: TakePhotoLifecycleObserver
    private lateinit var selectPreviewObserver: SelectPreviewLifecycleObserver
    private var takePhotoTempFile: File? = null
    private var clipImageFile: File? = null
    private var hasInitViews = false
    private var isCheckingPermission = false
    private var source: String = ""
    private var maxNum: Int = 1
    private var multiSelect = false
    private var mediaType: MediaType = MediaType.ALL
    private var clipParamData: ClipParamData? = null
    private var gifOpt: Boolean? = null
    private val fromPosition by fastLazy { intent.getIntExtra(KEY_FROM_POSITION, -1) }
    private val checkedMedias by fastLazy {
        intent.getParcelableArrayListExtra<LocalMedia>(KEY_SELECTED_MEDIA_LIST) ?: ArrayList()
    }
    private val videoMaxSecond by fastLazy { intent.getIntExtra(KEY_VIDEO_MAX_SECOND, -1) }
    private val imageMinSize by fastLazy { intent.getIntExtra(KEY_IMAGE_MIN_SIZE, -1) }
    private var topTipsString: CharSequence? = null // 顶部提示文字

    override fun onBeforeCreate() {
        super.onBeforeCreate()
        source = intent.getStringExtra(KEY_SOURCE) ?: ""
        maxNum = intent.getIntExtra(KEY_MAX_NUM, 1)
        multiSelect = maxNum > 1
        clipParamData = intent.getParcelableExtra(KEY_CLIP_PARAM_DATA)
        mediaType = (intent.getSerializableExtra(KEY_MEDIA_TYPE) as? MediaType) ?: MediaType.ALL
        gifOpt = intent.getBooleanExtra(KEY_GIF_OPTION, false)
        topTipsString = intent.getCharSequenceExtra(TOP_TIPS_STRING)

    }

    override fun initViews() {
        super.initViews()
        QMUIStatusBarHelper.setStatusBarLightMode(this)
        setContentView(binding.root)
        initObserver()
        checkPermission()
        updateMesText()
    }

    override fun observeViewModel() {
        super.observeViewModel()
        mediaSelectViewModel.selectFolderLD.observe(this) {
            onFolderSelected(it)
        }
    }

    override fun onResume() {
        super.onResume()
        if (!isCheckingPermission && !hasInitViews) {
            if (PermissionUtils.hasPermissions(this, *getMediaTypePermissionArray())) {
                initViewsAndShowImages()
            } else {
                showPermissionNoGrantedDialog()
            }
        }
    }

    @SuppressLint("CheckResult")
    private fun checkPermission() {
        isCheckingPermission = true
        if (!PermissionUtils.hasPermissions(this, *getMediaTypePermissionArray())) {
            PermissionUtils.getRxPermissions(this)
                .request(*getMediaTypePermissionArray()).subscribe { granted ->
                    isCheckingPermission = false
                    if (granted) {
                        initViewsAndShowImages()
                    } else {
                        showPermissionNoGrantedDialog()
                    }
                }
        } else {
            isCheckingPermission = false
            initViewsAndShowImages()
        }
    }

    private fun showPermissionNoGrantedDialog() {
        CommonDialog.Builder()
            .message(getCompatString(R.string.image_select_permission_no_granted))
            .onPositive {
                PermissionUtils.startPermissionSettingActivity(this)
            }
            .onNegative {
                finish()
            }
            .setShowDefaultCancel(true)
            .build()
            .show(supportFragmentManager)
    }

    private fun initViewsAndShowImages() {
        hasInitViews = true
        initView()
        mediaSelectViewModel.loadMedia(
            LoadMediaConfig(
                mediaType,
                gifOpt != true,
                selectedMediaList = checkedMedias
            )
        )
    }

    private fun initView() {
        binding.backIv.setOnClickListener {
            finish()
        }
        binding.imageFolderCl.setOnClickListener {
            hideFolders()
        }
        binding.expandDirClickArea.setOnClickListener {
            if (binding.imageFolderCl.visibility == View.GONE) {
                showFolders()
            } else {
                hideFolders()
            }
        }
        if (multiSelect) {
            binding.btnConfirm.show()
            binding.btnConfirm.setOnClickListener {
                val intent = Intent()
                intent.putParcelableArrayListExtra(SELECT_IMAGES, checkedMedias)
                intent.putExtra(KEY_SOURCE, source)
                setResult(RESULT_OK, intent)
                finish()
            }
        }
        selectImageListAdapter = MultiTypeAdapter()
        selectImageListAdapter.register(AddItemViewBinder(this))
        selectImageListAdapter.register(ImageItemViewBinder(this, multiSelect))

        imageFolderListAdapter = MultiTypeAdapter()
        imageFolderListAdapter.register(ImageFolderItemViewBinder(this))
        gridLayoutManager = GridLayoutManager(
            this@ImageSelectActivity,
            SPAN_COUNT,
            RecyclerView.VERTICAL,
            false
        )

        binding.imageListRv.apply {
            layoutManager = gridLayoutManager
            addItemDecoration(
                GridSpacingItemDecoration(
                    SPAN_COUNT,
                    DisplayUtil.dp2px(4f),
                    DisplayUtil.dp2px(4f),
                    true
                )
            )
            adapter = selectImageListAdapter
        }
        binding.imageFolderRv.apply {
            layoutManager = LinearLayoutManager(this@ImageSelectActivity)
            adapter = imageFolderListAdapter
        }
    }

    private fun initObserver() {
        clipImageObserver = object : ClipImageLifecycleObserver(activityResultRegistry) {
            override fun onResult(resultCode: Int, inputPath: String, outputPath: String) {
                if (resultCode == RESULT_CANCELED) {
                    return
                }

                onImageFileResult(clipImageFile?.absolutePath, resultCode)
            }
        }
        lifecycle.addObserver(clipImageObserver)
        takePhotoImagePath?.let {
            takePhotoTempFile = File(it, "${System.currentTimeMillis()}.jpg")
        }
        takePhotoObserver = object : TakePhotoLifecycleObserver(activityResultRegistry) {
            override fun onResult(resultCode: Int) {
                Log.i(TAG, "takePhotoObserver onResult: $resultCode")
                if (resultCode != RESULT_OK) {
                    return
                }
                handleTakePhotoResult()
            }
        }
        lifecycle.addObserver(takePhotoObserver)
        selectPreviewObserver = object : SelectPreviewLifecycleObserver(activityResultRegistry) {
            override fun onResult(result: SelectPreviewResult) {
                val resultCode = result.resultCode
                val path = result.path
                val uri = result.uri
                if (resultCode != RESULT_OK) {
                    return
                }
                if (multiSelect) {
                    return
                }
                finishResult(path, uri, resultCode, MediaType.IMAGE)
            }
        }
        lifecycle.addObserver(selectPreviewObserver)
    }

    private fun showFolders() {
        binding.imageFolderCl.visibility = View.VISIBLE
        imageFolderListAdapter.items = mediaSelectViewModel.foldersLD.value ?: arrayListOf()
        imageFolderListAdapter.notifyDataSetChanged()
    }

    private fun hideFolders() {
        binding.imageFolderCl.visibility = View.GONE
    }

    private fun clipImage(imageInfo: LocalMedia?) {
        imageInfo?.path?.let { inputFilePath ->
            clipImageFile = File(
                clipImagePath ?: filesDir.absolutePath,
                "${System.currentTimeMillis()}.jpg"
            )
            clipImageFile?.let { outputFile ->
                clipImageObserver.launch(
                    inputFilePath,
                    outputFile.absolutePath,
                    clipParamData ?: avatarClipParam
                )
            }
        }
    }

    private fun handleTakePhotoResult() {
        if (takePhotoTempFile?.exists() == true) {
            val clipParamData = clipParamData
            if (clipParamData != null) {
                clipImageFile = File(
                    clipImagePath ?: filesDir.absolutePath,
                    "${System.currentTimeMillis()}.jpg"
                )
                clipImageFile?.let {
                    clipImageObserver.launch(
                        takePhotoTempFile?.absolutePath ?: "",
                        it.absolutePath, clipParamData
                    )
                }
            } else {
                selectPreviewObserver.launch(
                    takePhotoTempFile?.absolutePath,
                    FileProvider7.getUriForFile(this@ImageSelectActivity, takePhotoTempFile)
                        ?.toString(),
                    source
                )
            }
        }
    }

    private fun onImageFileResult(filePath: String?, resultCode: Int = RESULT_OK) {
        var file: File? = null
        if (filePath != null) {
            file = File(filePath)
        }
        finishResult(
            filePath,
            FileProvider7.getUriForFile(this@ImageSelectActivity, file)?.toString(),
            resultCode,
            MediaType.IMAGE
        )
    }

    private fun finishResult(
        filePath: String?,
        fileUri: String?,
        resultCode: Int = RESULT_OK,
        mediaType: MediaType,
        localMedia: LocalMedia? = null
    ) {
        val intent = Intent()
        intent.putExtra(KEY_SOURCE, source)
        intent.putExtra(KEY_MEDIA_TYPE, mediaType)
        intent.putExtra(SELECT_IMAGE_PATH, filePath)
        intent.putExtra(SELECT_IMAGE_URI, fileUri)
        if (localMedia != null) {
            val mediaInfos = ArrayList<LocalMedia>().apply {
                add(localMedia)
            }
            intent.putParcelableArrayListExtra(SELECT_IMAGES, mediaInfos)
        }
        intent.putExtra(KEY_FROM_POSITION, fromPosition)
        setResult(resultCode, intent)
        finish()
    }

    private fun onFolderSelected(folder: LocalMediaFolder) {
        hideFolders()
        binding.imageDirNameTv.text = folder.name
        val mediaInfoList = arrayListOf<MediaInfo>()
        if (mediaType != MediaType.VIDEO) {
            mediaInfoList.add(AddInfo(mediaType = MediaType.Companion.getMediaType(folder.ofAllType)))
        }
        val localMediaList = folder.getImages()
        if (gifOpt == true) {
            localMediaList.sortBy { !PictureMimeType.isGif(it.mimeType) }
        }

        mediaInfoList.addAll(localMediaList)
        selectImageListAdapter.items = mediaInfoList
        selectImageListAdapter.notifyDataSetChanged()
    }

    override fun onBackPressed() {
        if (binding.imageFolderCl.visibility == View.VISIBLE) {
            hideFolders()
            return
        }

        super.onBackPressed()
    }

    override fun onDestroy() {
        super.onDestroy()
        videoCoverCache.evictAll()
    }

    override fun onSelectFolder(folderInfo: LocalMediaFolder) {
        mediaSelectViewModel.selectFolder(folderInfo)
    }

    override fun onSelectImage(imageInfo: LocalMedia) {
        if (imageMinSize > 0 && PictureMimeType.eqImage(imageInfo.mimeType) && !PictureMimeType.isGif(
                imageInfo.mimeType
            )
        ) {
            if (imageInfo.width < imageMinSize || imageInfo.height < imageMinSize) {
                showToast(R.string.photo_size_not_valid)
                return
            }
        }

        val clipParamData = clipParamData
        if (clipParamData != null && !PictureMimeType.isGif(imageInfo.mimeType)) {
            clipImage(imageInfo)
        } else {
            selectPreviewObserver.launch(imageInfo.path, imageInfo.uri, source, maxNum == 1)
        }
    }

    override fun onItemChecked(position: Int) {
        val item = selectImageListAdapter.items[position]
        if (item is LocalMedia) {
            if (!item.isChecked && checkedMedias.size >= maxNum) {
                return
            }

            if (imageMinSize > 0 && PictureMimeType.eqImage(item.mimeType) && !PictureMimeType.isGif(
                    item.mimeType
                )
            ) {
                if (item.width < imageMinSize || item.height < imageMinSize) {
                    showToast(R.string.photo_size_not_valid)
                    return
                }
            }
            if (item.isVideo() && videoMaxSecond > 0 && item.duration > videoMaxSecond * 1000L) {
                showToast(
                    getCompatString(
                        R.string.common_video_select_duration_limit_tip,
                        videoMaxSecond.toString()
                    )
                )
                return
            }

            item.isChecked = !item.isChecked

            if (item.isChecked) {
                checkedMedias.add(item)
                item.num = checkedMedias.size
                selectImageListAdapter.notifyItemChanged(position)
            } else {
                item.num = 0
                selectImageListAdapter.notifyItemChanged(position)

                // 中间的取消选择后, 从列表中移除, 并改变后面的数字
                val indexOf = checkedMedias.indexOf(item)
                if (indexOf != -1) {
                    checkedMedias.removeAt(indexOf)
                }
                for (i in indexOf until checkedMedias.size) {
                    val mediaInfo = checkedMedias[i]
                    mediaInfo.num = i + 1
                    selectImageListAdapter.notifyItemChanged(
                        selectImageListAdapter.items.indexOf(
                            mediaInfo
                        )
                    )
                }
            }
        }
    }

    override fun onSelectVideo(videoInfo: LocalMedia) {
        if (videoMaxSecond > 0 && videoInfo.duration > videoMaxSecond * 1000L) {
            showToast(
                getCompatString(
                    R.string.common_video_select_duration_limit_tip, videoMaxSecond.toString()
                )
            )
            return
        }
        finishResult(videoInfo.path, videoInfo.uri, RESULT_OK, MediaType.VIDEO, videoInfo)
    }

    override fun onTakeAll() {
        onTakePhoto()
    }

    @SuppressLint("CheckResult")
    override fun onTakePhoto() {
        if (PermissionUtils.hasPermissions(this, Manifest.permission.CAMERA)) {
            when (val rlt = App.instance.hardwareManager.checkHardwareAvailable(Hardware.CAMERA)) {
                is Rlt.Failed -> {
                    showToast(rlt.error.msg)
                }

                is Rlt.Success -> {
                    takePhotoTempFile?.let {
                        takePhotoObserver.launch(it)
                    }
                }
            }
        } else {
            PermissionUtils.getRxPermissions(this)
                .request(Manifest.permission.CAMERA).subscribe { granted ->
                    if (granted) {
                        when (val rlt =
                            App.instance.hardwareManager.checkHardwareAvailable(Hardware.CAMERA)) {
                            is Rlt.Failed -> {
                                showToast(rlt.error.msg)
                            }

                            is Rlt.Success -> {
                                takePhotoTempFile?.let {
                                    takePhotoObserver.launch(it)
                                }
                            }
                        }
                    }
                }
        }
    }

    override fun onTakeVideo() {

    }

    private fun getMediaTypePermissionArray(): Array<String> {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
            return arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE)
        }
        return when (mediaType) {
            MediaType.ALL -> {
                arrayOf(Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO)
            }

            MediaType.IMAGE -> {
                arrayOf(Manifest.permission.READ_MEDIA_IMAGES)
            }

            MediaType.VIDEO -> {
                arrayOf(Manifest.permission.READ_MEDIA_VIDEO)
            }
        }
    }

    private fun updateMesText() {
        //具体的文案由外部根据业务逻辑进行设置，内部只做展示处理
        if (topTipsString.isNullOrEmpty()){
            binding.selectMesTipTv.gone()
            return
        }
        binding.selectMesTipTv.show()
        binding.selectMesTipTv.text = topTipsString
    }


}