package com.adealink.weparty.share.qrcode.page

import android.Manifest
import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.os.Build
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.annotation.LayoutRes
import androidx.core.net.toUri
import androidx.lifecycle.lifecycleScope
import com.adealink.frame.aab.util.getCompatString
import com.adealink.frame.base.AppBase
import com.adealink.frame.coroutine.dispatcher.Dispatcher
import com.adealink.frame.ext.copyToAlbum
import com.adealink.frame.log.Log
import com.adealink.frame.util.AppUtil
import com.adealink.frame.util.ViewShotUtil
import com.adealink.frame.util.getFileName
import com.adealink.weparty.commonui.BaseActivity
import com.adealink.weparty.commonui.BaseFragment
import com.adealink.weparty.commonui.toast.util.showToast
import com.adealink.weparty.commonui.widget.CommonDialog
import com.adealink.weparty.constant.STORAGE_PERMISSION_DIALOG
import com.adealink.weparty.module.profile.ProfileModule
import com.adealink.weparty.permission.PermissionUtils
import com.adealink.weparty.share.R
import com.adealink.weparty.share.data.TAG_SHARE_QRCODE
import com.adealink.weparty.share.databinding.LayoutQrcodeOrderShotBinding
import com.adealink.weparty.share.qrcode.viewmodel.QRCodeOrderDetail
import com.adealink.weparty.storage.file.FilePath
import com.adealink.weparty.url.UrlConfig
import com.adealink.weparty.util.fetchImage
import com.adealink.weparty.util.formatNumberStr
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import com.adealink.weparty.R as APP_R

/**
 * 通用码生成规则
 * https://mimolive.sg.larksuite.com/wiki/Dic1wugYQiuSXQk6jWgl9OzNglc?from=from_copylink
 *
 * 测试环境:
 * https://test-web.gami.vip/user/category?id=xxxx&code=xxxx
 * 正式环境:
 * https://web.gami.vip/user/category?id=xxxx&code=xxxx
 *
 * 参数说明:
 * - id: 用户ID
 * - code: 后端二维码
 */
abstract class BaseQRCodeFragment(@LayoutRes contentLayoutId: Int) : BaseFragment(contentLayoutId) {

    var qrCodeBitmap: Bitmap? = null
    var qrCodeLink: String? = null

    var orderDetail: QRCodeOrderDetail? = null
    abstract fun orderPrice(): Float?

    abstract fun orderCount(): Int

    fun generateQRCode(detail: QRCodeOrderDetail): String {
        return UrlConfig.qrCodeShare.toUri().buildUpon().apply {
            appendQueryParameter("id", detail.category.id)
            appendQueryParameter("code", detail.order.qrCode)
        }.toString()
    }

    //保存图片需要检查存储权限
    @SuppressLint("CheckResult")
    fun checkStoragePermissionAndSaveQRCode() {
        val context = activity ?: return
        val permission = getMediaImagePermission()
        if (PermissionUtils.hasPermissions(context, *permission)) {
            shareQRCodeOrder()
        } else {
            PermissionUtils.getRxPermissions(context)
                .request(*permission).subscribe { granted ->
                    if (granted) {
                        shareQRCodeOrder()
                    } else {
                        showPermissionNoGrantedDialog()
                    }
                }
        }
    }

    private fun shareQRCodeOrder() {
        val qrCodeLink = qrCodeLink
        val qrCodeBitmap = qrCodeBitmap
        if (qrCodeLink.isNullOrEmpty() || qrCodeBitmap == null || qrCodeBitmap.isRecycled) {
            return
        }
        (activity as? BaseActivity)?.showLoading()
        viewLifecycleOwner.lifecycleScope.launch {
            try {
                val shotView = inflateShotView(qrCodeBitmap)
                if (shotView == null) {
                    throw IllegalStateException("inflateShotView fail")
                }
                val posterPath = generateQRCodeOrderBitmap(shotView)
                savePosterToAlbum(posterPath)
                showToast(R.string.share_save_poster_success)
            } catch (e: Exception) {
                Log.d(TAG_SHARE_QRCODE, "sharePoster fail, for ${e.message}", e)
                showToast(R.string.share_save_poster_fail)
            } finally {
                (activity as? BaseActivity)?.dismissLoading()
            }
        }
    }

    @SuppressLint("SetTextI18n")
    private suspend fun inflateShotView(qrCode: Bitmap?): View? {
        return withContext(Dispatcher.UI) {
            //加载模版布局
            val fragmentContentView = (view as? ViewGroup) ?: return@withContext null
            var shotViewContainer =
                fragmentContentView.findViewById<FrameLayout>(APP_R.id.id_shot_view_container)
            if (shotViewContainer == null) {
                shotViewContainer = FrameLayout(fragmentContentView.context).apply {
                    id = APP_R.id.id_shot_view_container
                    visibility = View.INVISIBLE
                }
                fragmentContentView.addView(shotViewContainer, ViewGroup.LayoutParams(0, 0))
            }

            var shotView = shotViewContainer.findViewById<View>(APP_R.id.id_shot_view)
            if (shotView == null) {
                shotView =
                    LayoutInflater.from(context)
                        .inflate(R.layout.layout_qrcode_order_shot, null, false)
                shotView.id = APP_R.id.id_shot_view
                shotViewContainer.addView(
                    shotView,
                    FrameLayout.LayoutParams(SHOT_WIDTH, SHOT_HEIGHT)
                )
            }

            val myUserInfo = ProfileModule.getMyUserInfo()
            val shotViewBinding = LayoutQrcodeOrderShotBinding.bind(shotView)
            shotViewBinding.ivAvatar.setImageBitmap(fetchImage(myUserInfo?.avatar))
            shotViewBinding.tvName.text = myUserInfo?.nickName
            shotViewBinding.vStar.setScore(myUserInfo?.star ?: 0f)
            if (qrCode != null && !qrCode.isRecycled) {
                shotViewBinding.ivQrCode.setImageBitmap(qrCode)
            }
            shotViewBinding.tvCurrency.text =
                formatNumberStr((orderDetail?.category?.price ?: 0f) * orderCount(), false)
            shotViewBinding.ivCategory.setImageBitmap(fetchImage(orderDetail?.category?.icon))
            shotViewBinding.tvCategory.text = orderDetail?.category?.name
            shotViewBinding.tvUnit.text = "${orderCount()} ${orderDetail?.category?.unit ?: ""}"
            shotView
        }
    }

    private suspend fun generateQRCodeOrderBitmap(shotView: View): String? {
        return withContext(Dispatcher.WENEXT_THREAD_POOL) {
            delay(200) //延迟200毫秒是为了让主线程可以渲染
            //创建 Bitmap 并绘制
            val savePath = FilePath.shareImagePath
            if (savePath.isNullOrEmpty()) {
                Log.e(TAG_SHARE_QRCODE, "shotViewAndSave fail, for shareImagePath is null.")
                return@withContext null
            }
            val shotPath = ViewShotUtil.of(shotView)
                .setSavePath(savePath)
                .setFilename("${SHOT_IMG_NAME_PREFIX}_${System.currentTimeMillis()}")
                .minWidth(SHOT_WIDTH)
                .maxWidth(SHOT_WIDTH)
                .toPNG()
                .save()
            if (shotPath.isNullOrEmpty()) {
                Log.e(
                    TAG_SHARE_QRCODE,
                    "shotViewAndSave fail, for ViewShot fail."
                )
                return@withContext null
            }
            return@withContext shotPath
        }
    }

    private suspend fun savePosterToAlbum(posterPath: String?) {
        return withContext(Dispatcher.WENEXT_THREAD_POOL) {
            if (posterPath.isNullOrEmpty()) {
                Log.d(TAG_SHARE_QRCODE, "saveImage fail, for shotView fail.")
                return@withContext
            }
            val imgName = getFileName(posterPath)
            if (imgName.isNullOrEmpty()) {
                Log.d(TAG_SHARE_QRCODE, "saveImage fail, for can not find imgName.")
                return@withContext
            }
            withContext(Dispatcher.WENEXT_THREAD_POOL) {
                File(posterPath).copyToAlbum(AppUtil.appContext, imgName, AppBase.appName)
            }
        }
    }

    private fun getMediaImagePermission(): Array<String> {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            arrayOf(Manifest.permission.READ_MEDIA_IMAGES)
        } else {
            arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
        }
    }

    private fun showPermissionNoGrantedDialog() {
        val permissionDialog = CommonDialog.Builder()
            .message(getCompatString(APP_R.string.toast_storage_permission_no_granted))
            .onPositive {
                PermissionUtils.startPermissionSettingActivity(activity)
            }
            .dismissAfterClick(true)
            .setShowDefaultCancel(true)
            .build()
        permissionDialog.show(childFragmentManager, STORAGE_PERMISSION_DIALOG)
    }

    override fun onDestroyView() {
        super.onDestroyView()
        qrCodeBitmap?.recycle()
        qrCodeBitmap = null
    }

    companion object {

        private const val SHOT_IMG_NAME_PREFIX = "order_"
        private const val SHOT_WIDTH = 750 //像素
        private const val SHOT_HEIGHT = 1000 //像素
    }

}