package com.gh.gamecenter.category2

import android.content.Context
import android.graphics.Color
import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.blankj.utilcode.util.KeyboardUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toResString
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.PopSearchCategoryBinding
import com.gh.gamecenter.entity.CategoryEntity
import io.reactivex.Single
import io.reactivex.disposables.CompositeDisposable
import me.xdrop.fuzzywuzzy.FuzzySearch

class SearchCategoryPop(
    height: Int,
    private val isAutoRequestFocus: Boolean,
    private val pageId: String,
    private val pageName: String,
    private val binding: PopSearchCategoryBinding
) : BugFixedPopupWindow(binding.root, ViewGroup.LayoutParams.MATCH_PARENT, height) {

    private var listener: OnSearchCategoryListener? = null
    private val handler = Handler(Looper.getMainLooper())
    private var searchDataList: List<CategoryV2ViewModel.SelectedTags>? = null

    private val compositeDisposable = CompositeDisposable()

    private var isSearching = false

    private val adapter by lazy {
        CategoryDirectoryAdapter(object : OnSearchCategoryListener {
            override fun isEnableSelected(): Boolean {
                return listener?.isEnableSelected() ?: false
            }

            override fun onItemSelected(selected: CategoryV2ViewModel.SelectedTags) {
                listener?.onItemSelected(selected)

            }

            override fun onItemRemoved(parentId: String, subCategoryId: String) {
                listener?.onItemRemoved(parentId, subCategoryId)
            }

            override fun onResetSelected() {
                listener?.onResetSelected()
            }

            override fun onSubmit() {
                listener?.onSubmit()
            }

        })
    }

    private val resultAdapter by lazy {
        SearchCategoryResultsAdapter {
            SensorsBridge.logClassificationSearchReturnClick(
                pageId,
                pageName,
                binding.searchView.searchKey,
                it.category.name ?: ""
            )
            if (listener?.isEnableSelected() == true) {
                clearSearchKey()
                listener?.onItemSelected(it)
            } else {
                ToastUtils.toast(R.string.selected_category_tags_max_toast.toResString())
            }

        }
    }

    private val selectedTagAdapter by lazy {
        SelectedTagsAdapter {
            listener?.onItemRemoved(it.parentId, it.category.id)
        }
    }

    init {
        isOutsideTouchable = true
        setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        isFocusable = true
        inputMethodMode = INPUT_METHOD_NEEDED
        softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING

        initView()

    }

    private fun initView() {
        binding.rvCategory.layoutManager = LinearLayoutManager(binding.root.context)
        binding.rvCategory.adapter = adapter

        binding.tvSelectedNumber.typeface =
            Typeface.createFromAsset(binding.root.context.assets, Constants.DIN_FONT_PATH)

        binding.root.setOnClickListener {
            dismiss()
        }

        binding.clContent.setOnClickListener {
            // 不需要具体实现，只是为了拦截 root 的点击事件
        }

        binding.tvReset.setOnClickListener {
            listener?.onResetSelected()
        }

        binding.vSubmit.setOnClickListener {
            dismiss()
            listener?.onSubmit()
        }

        binding.searchView.addTextChangedListener {
            handler.removeCallbacksAndMessages(null)
            val key = it?.toString() ?: ""
            if (key.isEmpty()) {
                changeToSearching(false)
            } else {
                handler.postDelayed({
                    search(it?.toString() ?: "")
                }, SEARCH_DELAY_DURATION)
            }
        }

        if (!isAutoRequestFocus) {
            binding.searchView.setEditTextOnFocusChangeListener { _, hasFocus ->
                if (hasFocus) {
                    SensorsBridge.logClassificationSearch(pageId, pageName)
                }
            }
        }

    }

    fun setData(data: List<CategoryEntity>) {
        searchDataList = data
            .asSequence()
            .mapIndexed { index, parent ->
                parent.data?.mapIndexed { childIndex, child ->
                    CategoryV2ViewModel.SelectedTags(parent.id, parent.name ?: "", index, child, childIndex)
                } ?: listOf()
            }
            .flatten()
            .toList()

        adapter.setListData(data)
    }

    fun updateCategorySelected(selectedList: List<CategoryV2ViewModel.SelectedTags>?) {
        val size = selectedList?.size ?: 0
        binding.tvSelectedNumber.goneIf(size == 0) {
            binding.tvSelectedNumber.text = "$size"
        }

        if (binding.rvSelected.adapter == null) {
            binding.rvSelected.layoutManager =
                LinearLayoutManager(binding.root.context, RecyclerView.HORIZONTAL, false)
            binding.rvSelected.adapter = selectedTagAdapter
        }
        selectedTagAdapter.submitList(selectedList)
        binding.rvSelected.goneIf(selectedList.isNullOrEmpty())

        if (isSearching) {
            search(binding.searchView.searchKey)
        }
    }

    private fun search(key: String) {
        Single.create {
            val data = searchDataList?.filterNot { item -> item.category.selected } ?: emptyList()
            val resultList = FuzzySearch.extractSorted(key, data, { item -> item.category.name ?: "" }, 1)
                .map { item -> item.referent }
            it.onSuccess(resultList)
        }.compose(singleToMain())
            .subscribe(object : BiResponse<List<CategoryV2ViewModel.SelectedTags>>() {
                override fun onSuccess(data: List<CategoryV2ViewModel.SelectedTags>) {
                    val hasResult = data.isNotEmpty()
                    SensorsBridge.logClassificationSearchReturn(pageId, pageName, key, hasResult)
                    changeToSearching(true, key, data)
                }

                override fun onFailure(exception: Exception) {
                    SensorsBridge.logClassificationSearchReturn(pageId, pageName, key, false)
                    changeToSearching(true, key)
                }
            }).let(compositeDisposable::add)
    }

    private fun clearSearchKey() {
        binding.searchView.clear()
    }

    private fun changeToSearching(
        isSearching: Boolean,
        key: String = "",
        results: List<CategoryV2ViewModel.SelectedTags>? = null
    ) {
        this.isSearching = isSearching
        binding.rvCategory.goneIf(isSearching)
        binding.rvResults.goneIf(results.isNullOrEmpty()) {
            if (binding.rvResults.adapter == null) {
                binding.rvResults.layoutManager = LinearLayoutManager(binding.rvResults.context)
                binding.rvResults.adapter = resultAdapter
            }
        }
        resultAdapter.setData(results ?: listOf(), key)
        binding.reuseNoConnection.root.goneIf(!isSearching || !results.isNullOrEmpty()) {
            binding.reuseNoConnection.reuseNoneDataTv.text = R.string.no_relevant_content_found.toResString()
            binding.reuseNoConnection.reuseNoneDataDescTv.goneIf(false)
            binding.reuseNoConnection.reuseNoneDataDescTv.text = R.string.try_a_different_search_term.toResString()
        }
    }

    fun setOnSearchCategoryListener(listener: OnSearchCategoryListener) {
        this.listener = listener
    }

    fun notifyItemSelectedChanged(parentId: String) {
        adapter.notifyItemSelectedChanged(parentId)
    }

    override fun showAtLocation(parent: View?, gravity: Int, x: Int, y: Int) {
        super.showAtLocation(parent, gravity, x, y)
        if (isAutoRequestFocus) {
            binding.searchView.requestFocus()
            handler.removeCallbacksAndMessages(null)
            // 在某些机型上延时一下才能弹起软键盘
            handler.postDelayed({
                KeyboardUtils.showSoftInput()
            }, SHOW_SOFT_INPUT_DELAY)
        }
    }

    override fun dismiss() {
        super.dismiss()
        clearSearchKey()
        handler.removeCallbacksAndMessages(null)
        compositeDisposable.clear()
    }


    companion object {

        private const val SEARCH_DELAY_DURATION = 300L
        private const val SHOW_SOFT_INPUT_DELAY = 200L

        fun newInstance(
            context: Context,
            height: Int,
            isAutoRequestFocus: Boolean,
            pageId: String,
            pageName: String
        ): SearchCategoryPop {
            val inflater = LayoutInflater.from(context)
            val binding = PopSearchCategoryBinding.inflate(inflater)
            return SearchCategoryPop(height, isAutoRequestFocus, pageId, pageName, binding)
        }
    }

    interface OnSearchCategoryListener {

        fun isEnableSelected(): Boolean

        fun onItemSelected(selected: CategoryV2ViewModel.SelectedTags)

        fun onItemRemoved(parentId: String, subCategoryId: String)

        fun onResetSelected()

        fun onSubmit()

    }
}