package com.adealink.weparty.order.detail

import android.annotation.SuppressLint
import android.os.Build
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.text.style.TypefaceSpan
import androidx.activity.viewModels
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.GridLayoutManager
import com.adealink.frame.aab.util.getCompatColor
import com.adealink.frame.aab.util.getCompatDimension
import com.adealink.frame.aab.util.getCompatString
import com.adealink.frame.base.Rlt
import com.adealink.frame.base.fastLazy
import com.adealink.frame.ext.findAndSetSpan
import com.adealink.frame.mvvm.view.viewBinding
import com.adealink.frame.router.Router
import com.adealink.frame.router.annotation.BindExtra
import com.adealink.frame.router.annotation.RouterUri
import com.adealink.frame.util.formatTime
import com.adealink.frame.util.onClick
import com.adealink.frame.util.removeUiCallbacks
import com.adealink.weparty.R
import com.adealink.weparty.commonui.BaseActivity
import com.adealink.weparty.commonui.DEFAULT_FONT_BOLD
import com.adealink.weparty.commonui.ext.dp
import com.adealink.weparty.commonui.ext.gone
import com.adealink.weparty.commonui.ext.show
import com.adealink.weparty.commonui.ext.sp
import com.adealink.weparty.commonui.recycleview.adapter.MultiTypeListAdapter
import com.adealink.weparty.commonui.recycleview.itemdecoration.GridSpacingItemDecoration
import com.adealink.weparty.commonui.toast.util.showFailedToast
import com.adealink.weparty.commonui.widget.CommonDialog
import com.adealink.weparty.module.image.data.PhotoData
import com.adealink.weparty.module.order.Order
import com.adealink.weparty.module.order.data.ORDER_EXPIRED_TS
import com.adealink.weparty.module.order.data.OrderDetailData
import com.adealink.weparty.module.order.data.OrderDetailInfo
import com.adealink.weparty.module.order.data.OrderStatus
import com.adealink.weparty.module.order.util.getUserOrderStatusText
import com.adealink.weparty.order.databinding.ActivityOrderDetailBinding
import com.adealink.weparty.order.dialog.EvaluateOrderDialog
import com.adealink.weparty.order.refund.PlaymateEvidenceActivity
import com.adealink.weparty.order.refund.adapter.PhotoItemViewBinder
import com.adealink.weparty.order.refund.data.BasePhotoItemData
import com.adealink.weparty.order.refund.data.PhotoItemData
import com.adealink.weparty.order.util.getOrderAllCost
import com.adealink.weparty.order.viewmodel.OrderViewModel
import com.adealink.weparty.order.viewmodel.OrderViewModelFactory
import com.adealink.weparty.order.viewmodel.UserOrderViewModel
import com.adealink.weparty.util.TIME_FORMAT_DMY_HMS
import com.adealink.weparty.util.applyImmersive
import com.adealink.weparty.util.formatNumber
import com.adealink.weparty.util.goImagePreviewActivity
import okhttp3.internal.format
import kotlin.math.max

@RouterUri(path = [Order.Detail.PATH], desc = "订单详情")
class OrderDetailActivity : BaseActivity() {

    companion object {
        private const val TAG = "OrderListActivity"
    }

    @BindExtra(Order.Detail.EXTRA_ORDER_ID)
    var orderId: String? = null

    @BindExtra(Order.Detail.EXTRA_ORDER_DETAIL)
    var orderInfo: OrderDetailInfo? = null

    private var orderDetail: OrderDetailData? = null

    private val binding by viewBinding(ActivityOrderDetailBinding::inflate)

    private val pictureAdapter by fastLazy { MultiTypeListAdapter<BasePhotoItemData>() }
    private val orderViewModel by viewModels<OrderViewModel> { OrderViewModelFactory() }
    private val userOrderViewModel by viewModels<UserOrderViewModel> { OrderViewModelFactory() }

    override fun onBeforeCreate() {
        super.onBeforeCreate()
        Router.bind(this)
    }

    override fun initViews() {
        super.initViews()
        setContentView(binding.root)
        applyImmersive { top ->
            binding.topBar.setPadding(0, top, 0, 0)
            binding.topBar.updateLayoutParams<ConstraintLayout.LayoutParams> {
                height = top + getCompatDimension(R.dimen.common_top_bar_height).toInt()
            }
        }

        binding.btnCancel.onClick {
            clickCancel()
        }
        binding.btnRefund.onClick {
            clickRefund()
        }
        binding.btnComplete.onClick {
            clickComplete()
        }
        binding.btnEvaluate.onClick {
            clickEvaluate()
        }

        pictureAdapter.register(
            PhotoItemViewBinder(
                onItemClick = {
                    previewPicture(it.data)
                },
                onDeleteClick = {
                }
            ))
        binding.rvReasonPicture.adapter = pictureAdapter
        binding.rvReasonPicture.layoutManager =
            GridLayoutManager(this, PlaymateEvidenceActivity.Companion.PICTURE_SPAN)
        binding.rvReasonPicture.addItemDecoration(
            GridSpacingItemDecoration(
                PlaymateEvidenceActivity.Companion.PICTURE_SPAN,
                4.dp(),
                4.dp(),
                false
            )
        )

        val orderData = this@OrderDetailActivity.orderInfo
        if (orderData != null) {
            updateOrderDetail(OrderDetailData(orderData, null, null, null, null))
        }
    }

    override fun onResume() {
        super.onResume()
        val orderId = this.orderInfo?.orderId ?: this@OrderDetailActivity.orderId
        if (!orderId.isNullOrEmpty()) {
            orderViewModel.loadOrderDetail(orderId).observe(this) { rlt ->
                when (rlt) {
                    is Rlt.Failed -> {
                        showFailedToast(rlt)
                    }

                    is Rlt.Success -> {
                        updateOrderDetail(rlt.data)
                    }
                }
            }
        }
    }

    override fun observeViewModel() {
        super.observeViewModel()
        userOrderViewModel.orderDetailLD.observeWithoutCache(this) {
            updateOrderDetail(it)
        }
    }

    @SuppressLint("SetTextI18n")
    private fun updateOrderDetail(data: OrderDetailData?) {
        this.orderDetail = data
        val orderStatus = OrderStatus.Companion.map(data?.order?.status)
        binding.ivOrderStatus.setImageResource(
            getUserOrderStatusIcon(
                orderStatus,
                data?.order?.refundApply
            )
        )
        binding.tvOrderStatus.text = getUserOrderStatusText(orderStatus, data?.order?.refundApply)

        if (data?.order?.refundApply == true
            || data?.order?.status == OrderStatus.USER_REFUND.status
            || data?.order?.status == OrderStatus.PLAYMATE_REFUSE.status
            || data?.order?.status == OrderStatus.USER_CANCEL.status
        ) {
            binding.ivTopBg.setImageResource(com.adealink.weparty.order.R.drawable.order_detail_top_cancel_bg)
        } else {
            binding.ivTopBg.setImageResource(com.adealink.weparty.order.R.drawable.order_detail_top_bg)
        }

        binding.ivOrderAvatar.setImageUrl(data?.order?.avatar)
        binding.tvOrderName.text = data?.order?.nickname

        binding.tvProductTypeDetail.text = data?.order?.categoryName
        binding.tvProductPriceDetail.text = formatNumber(data?.order?.price ?: 0f, false)
        binding.tvOrderCountDetail.text = "${data?.order?.unit} x${data?.order?.purchaseQty}"

        val totalAmount = data?.order?.totalAmount
        val targetAmount = (data?.order?.price ?: 0f) * (data?.order?.purchaseQty ?: 0)
        if (totalAmount != null && totalAmount > 0 && totalAmount < targetAmount) {
            binding.clDiscount.show()
            binding.tvOrderDiscountDetail.text = formatNumber(-(targetAmount - totalAmount), false)
        } else {
            binding.clDiscount.gone()
        }

        if (data?.order?.customerRemark.isNullOrEmpty()) {
            binding.clOrderRemark.gone()
        } else {
            binding.clOrderRemark.show()
            binding.tvOrderRemarkDetail.text = data?.order?.customerRemark
        }
        binding.tvOrderIdDetail.text = data?.order?.orderId
        binding.tvOrderTimeDetail.text =
            formatTime(data?.order?.createTime ?: 0, TIME_FORMAT_DMY_HMS)
        binding.tvOrderCostDetail.text =
            getOrderAllCost(
                data?.order?.price ?: 0f,
                data?.order?.purchaseQty ?: 0,
                data?.order?.totalAmount,
                16.sp(),
                16.dp()
            )

        if (data?.order?.refundApply == true) {
            binding.clOrderCancel.gone()
            binding.clOrderInProgress.gone()
            binding.clOrderFinish.gone()
        } else {
            when (orderStatus) {
                OrderStatus.CREATE_ORDER,
                OrderStatus.WAIT_FOR_ACCEPT -> {
                    binding.clOrderCancel.show()
                    binding.clOrderInProgress.gone()
                    binding.clOrderFinish.gone()
                }

                OrderStatus.PLAYMATE_ACCEPT,
                OrderStatus.PLAYMATE_IN_SERVICE -> {
                    binding.clOrderCancel.gone()
                    binding.clOrderInProgress.show()
                    binding.btnRefund.show()
                    binding.btnComplete.gone()
                    binding.clOrderFinish.gone()
                }

                OrderStatus.PLAYMATE_END_SERVICE -> {
                    binding.clOrderCancel.gone()
                    binding.clOrderInProgress.show()
                    binding.btnRefund.show()
                    binding.btnComplete.show()
                    binding.clOrderFinish.gone()
                }

                OrderStatus.PLAYMATE_REFUSE,
                OrderStatus.USER_CANCEL,
                OrderStatus.USER_REFUND -> {
                    binding.clOrderCancel.gone()
                    binding.clOrderInProgress.gone()
                    binding.clOrderFinish.gone()
                }

                OrderStatus.COMPLETE -> {
                    binding.clOrderCancel.gone()
                    binding.clOrderInProgress.gone()
                    if (data?.order?.star == null || !data.order.hasEvaluate()) {
                        binding.vEvaluate.gone()
                        binding.clOrderFinish.show()
                    } else {
                        binding.vEvaluate.show()
                        binding.vEvaluate.setScore(data.order.star ?: 0f)
                        binding.clOrderFinish.gone()
                    }
                }

                null -> {

                }
            }
        }

        if (data?.order?.refundApply == true) {
            binding.clUserRefund.show()
            binding.tvReason.text = data.refundReason
            val imageItemList = data.refundAttachments?.map {
                PhotoItemData(
                    PhotoData(url = it.attachmentUrl, path = null, uri = null),
                    showDelete = false
                )
            }
            if (imageItemList.isNullOrEmpty()) {
                binding.tvReasonPictureTitle.gone()
                binding.rvReasonPicture.gone()
            } else {
                binding.tvReasonPictureTitle.show()
                binding.rvReasonPicture.show()
                pictureAdapter.submitList(imageItemList)
            }
        } else {
            binding.clUserRefund.gone()
        }

        if (data?.order?.isPendingAccept() == true) {
            val endTs = data.order.createTime + ORDER_EXPIRED_TS
            this.countDownSecond = max(endTs - System.currentTimeMillis(), 0) / 1000
            startReplyCountDown(0)
        } else {
            this.countDownSecond = 0
            stopReplyCountDown()
        }
    }


    private fun getUserOrderStatusIcon(
        status: OrderStatus?,
        isRefundApply: Boolean? //是否处于申请退款中
    ): Int {
        if (isRefundApply == true) {
            return com.adealink.weparty.order.R.drawable.order_status_in_progress_ic
        }
        return when (status) {
            OrderStatus.CREATE_ORDER -> {
                com.adealink.weparty.order.R.drawable.order_status_in_progress_ic
            }

            OrderStatus.WAIT_FOR_ACCEPT -> {
                com.adealink.weparty.order.R.drawable.order_status_in_progress_ic
            }

            OrderStatus.PLAYMATE_ACCEPT -> {
                com.adealink.weparty.order.R.drawable.order_status_accept_ic
            }

            OrderStatus.PLAYMATE_IN_SERVICE -> {
                com.adealink.weparty.order.R.drawable.order_status_in_progress_ic
            }

            OrderStatus.PLAYMATE_END_SERVICE -> {
                com.adealink.weparty.order.R.drawable.order_status_in_progress_ic
            }

            OrderStatus.PLAYMATE_REFUSE -> {
                com.adealink.weparty.order.R.drawable.order_status_cancel_ic
            }

            OrderStatus.COMPLETE -> {
                com.adealink.weparty.order.R.drawable.order_status_finish_ic
            }

            OrderStatus.USER_REFUND -> {
                com.adealink.weparty.order.R.drawable.order_status_finish_ic
            }

            OrderStatus.USER_CANCEL -> {
                com.adealink.weparty.order.R.drawable.order_status_cancel_ic
            }

            null -> {
                com.adealink.weparty.order.R.drawable.order_status_in_progress_ic
            }
        }
    }

    private var countDownSecond: Long = 0

    private val countDownRunnable = Runnable {
        updateCountDownText()
        countDownSecond = max(0, countDownSecond - 1)
        startReplyCountDown(1000)
    }

    private fun startReplyCountDown(delay: Long = 1000) {
        if (orderDetail?.order?.isPendingAccept() == false) {
            binding.tvAcceptCountDown.gone()
            return
        }
        binding.tvAcceptCountDown.show()
        updateCountDownText()
        if (countDownSecond >= 0) {
            removeUiCallbacks(countDownRunnable)
            com.adealink.frame.util.runOnUiThread(countDownRunnable, delay)
        }
    }

    private fun stopReplyCountDown() {
        binding.tvAcceptCountDown.gone()
        removeUiCallbacks(countDownRunnable)
    }

    @SuppressLint("SetTextI18n")
    private fun updateCountDownText() {
        val minute = countDownSecond / 60
        val second = countDownSecond % 60

        val timeStr = "${format("%02d", minute)}:${format("%02d", second)}"
        val text =
            getCompatString(com.adealink.weparty.order.R.string.order_auto_cancel_title, timeStr)
        binding.tvAcceptCountDown.text = SpannableStringBuilder(text).apply {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                findAndSetSpan(TypefaceSpan(DEFAULT_FONT_BOLD), timeStr)
            }
            findAndSetSpan(
                ForegroundColorSpan(getCompatColor(R.color.color_FF1789FF)),
                timeStr
            )
        }
    }

    private fun clickCancel() {
        fun cancel() {
            val data = orderDetail?.order ?: return
            showLoading()
            userOrderViewModel.cancelOrder(data).observe(this) { rlt ->
                dismissLoading()
                showFailedToast(rlt)
            }
        }

        CommonDialog.Builder()
            .title(getCompatString(R.string.common_user_cancel_order_tips))
            .positiveText(getCompatString(R.string.commonui_confirm))
            .setShowDefaultCancel(true)
            .onPositive {
                cancel()
            }
            .show(supportFragmentManager)
    }

    private fun clickRefund() {
        val data = orderDetail?.order ?: return
        Router.build(this, Order.Refund.PATH)
            .putExtra(Order.Refund.EXTRA_ORDER_DETAIL, data)
            .start()
    }

    private fun clickComplete() {
        fun complete() {
            val data = orderDetail?.order ?: return
            showLoading()
            userOrderViewModel.completeOrder(data).observe(this) { rlt ->
                dismissLoading()
                showFailedToast(rlt)
            }
        }

        CommonDialog.Builder()
            .title(getCompatString(R.string.common_user_complete_order_tips))
            .positiveText(getCompatString(R.string.commonui_confirm))
            .setShowDefaultCancel(true)
            .onPositive {
                complete()
            }
            .show(supportFragmentManager)
    }

    private fun clickEvaluate() {
        val data = orderDetail?.order ?: return
        EvaluateOrderDialog().apply {
            setOrderInfo(data)
            setListener(object : EvaluateOrderDialog.OnEvaluateListener {
                override fun onEvaluate(star: Float, comment: String) {
                    orderDetail?.order?.star = star
                    updateOrderDetail(orderDetail)
                }
            })
        }.show(supportFragmentManager, "EvaluateOrderDialog")
    }

    private fun previewPicture(data: PhotoData) {
        val uri = data.uri
        if (uri.isNullOrEmpty()) {
            return
        }
        goImagePreviewActivity(
            this,
            arrayListOf(uri)
        )
    }

}