package com.player.musicoo.fragment

import android.annotation.SuppressLint
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.text.Editable
import android.text.TextWatcher
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.TextView
import android.widget.TextView.OnEditorActionListener
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.flexbox.AlignItems
import com.google.android.flexbox.FlexWrap
import com.google.android.flexbox.FlexboxLayoutManager
import com.google.android.flexbox.JustifyContent
import com.gyf.immersionbar.ktx.immersionBar
import com.player.musicoo.adapter.SearchHistoryAdapter
import com.player.musicoo.adapter.SearchSuggestionsAdapter
import com.player.musicoo.databinding.FragmentSearchBinding
import com.player.musicoo.innertube.Innertube
import com.player.musicoo.innertube.models.bodies.SearchBody
import com.player.musicoo.innertube.models.bodies.SearchSuggestionsBody
import com.player.musicoo.innertube.requests.moSearchPage
import com.player.musicoo.innertube.requests.searchSuggestions
import com.player.musicoo.util.LogTag
import com.player.musicoo.view.SearchResultOptimalView
import com.player.musicoo.view.SearchResultOtherView
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive
import kotlinx.coroutines.selects.select

class SearchFragment : MoBaseFragment<FragmentSearchBinding>(), TextWatcher,
    View.OnFocusChangeListener, SearchSuggestionsAdapter.OnItemClickListener,
    OnEditorActionListener, SearchHistoryAdapter.HistoryOnItemClickListener {

    interface SearchFragmentCancelClickListener {
        fun onFragmentClick()
    }

    fun setButtonClickListener(listener: SearchFragmentCancelClickListener) {
        this.buttonClickListener = listener
    }

    private var buttonClickListener: SearchFragmentCancelClickListener? = null

    private val requests: Channel<Request> = Channel(Channel.UNLIMITED)

    sealed class Request {
        data object SearchSuggestions : Request()
        data class SearchData(val input: String) : Request()
    }

    private var searchSuggestionsAdapterAdapter: SearchSuggestionsAdapter? = null
    private var searchSuggestionsList: MutableList<String> = mutableListOf()
    private var searchHistorySet: MutableSet<String> = mutableSetOf()
    private var searchHistory: MutableList<String> = mutableListOf()
    private var searchHistoryAdapter: SearchHistoryAdapter? = null

    override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentSearchBinding
        get() = FragmentSearchBinding::inflate

    override suspend fun onViewCreated() {
        initView()
        initSearchSuggestionsAdapter()
        initSearchHistoryAdapter()
        initImmersionBar()
        onReceive()
    }

    private fun initView() {
        binding.cancelBtn.setOnClickListener {
            buttonClickListener?.onFragmentClick()
        }
        binding.searchEdit.let {
            it.setOnEditorActionListener(this)
            it.addTextChangedListener(this)
            it.onFocusChangeListener = this
            it.requestFocus()
        }
        binding.deleteInputBtn.setOnClickListener {
            binding.searchEdit.text.clear()
        }
        binding.deleteHistoryBtn.setOnClickListener {
            appStore.searchHistoryStore = emptySet()
            updateHistoryUi()
        }
    }

    private fun initSearchSuggestionsAdapter() {
        searchSuggestionsAdapterAdapter =
            SearchSuggestionsAdapter(requireActivity(), searchSuggestionsList)
        searchSuggestionsAdapterAdapter?.setOnItemClickListener(this)
        binding.searchSuggestionsRv.layoutManager = LinearLayoutManager(
            requireActivity(),
            LinearLayoutManager.VERTICAL,
            false
        )
        binding.searchSuggestionsRv.adapter = searchSuggestionsAdapterAdapter
    }

    private fun initSearchHistoryAdapter() {
        searchHistoryAdapter =
            SearchHistoryAdapter(requireActivity(), searchHistory)
        searchHistoryAdapter?.setOnItemClickListener(this)
        val layoutManager = FlexboxLayoutManager(requireActivity())
        layoutManager.flexWrap = FlexWrap.WRAP // 设置换行方式为自动换行
        layoutManager.alignItems = AlignItems.STRETCH // 设置项目在副轴上的对齐方式为拉伸
        layoutManager.justifyContent = JustifyContent.FLEX_START // 设置主轴上的对齐方式为起始端对齐
        binding.historyRv.layoutManager = layoutManager

        binding.historyRv.adapter = searchHistoryAdapter

        updateHistoryUi()
    }

    @SuppressLint("NotifyDataSetChanged")
    private fun updateHistoryUi() {
        searchHistory.clear()
        searchHistory.addAll(appStore.searchHistoryStore)
        searchHistoryAdapter?.notifyDataSetChanged()
        if (appStore.searchHistoryStore.isNotEmpty()) {
            binding.historyLayout.visibility = View.VISIBLE
        } else {
            binding.historyLayout.visibility = View.GONE
        }
    }

    private fun initImmersionBar() {
        immersionBar {
            statusBarDarkFont(false)
            statusBarView(binding.view)
        }
    }

    @SuppressLint("NotifyDataSetChanged", "SetTextI18n")
    private suspend fun onReceive() {
        while (isActive) {
            select<Unit> {
                requests.onReceive {
                    when (it) {
                        is Request.SearchSuggestions -> {
                            val input = binding.searchEdit.text.toString().trim()
                            Innertube.searchSuggestions(SearchSuggestionsBody(input = input))
                                ?.onSuccess { suggestionsList ->
                                    LogTag.LogD(TAG, "suggestionsList->${suggestionsList?.size}")
                                    if (suggestionsList != null) {
                                        showSearchSuggestions()
                                        searchSuggestionsList.clear()
                                        searchSuggestionsList.addAll(suggestionsList)
                                        searchSuggestionsAdapterAdapter?.notifyDataSetChanged()
                                    } else {
                                        binding.searchSuggestionsLayout.visibility = View.GONE
                                    }
                                }?.onFailure { error ->
                                    LogTag.LogD(TAG, "searchSuggestions onFailure->${error}")
                                    binding.searchSuggestionsLayout.visibility = View.GONE
                                }
                        }

                        is Request.SearchData -> {
                            binding.contentLayout.removeAllViews()
                            binding.searchEdit.clearFocus()
                            showLoadingLayout()
                            val input = it.input
                            if (input.isNotEmpty()) {
                                searchHistorySet.clear()
                                searchHistorySet.addAll(appStore.searchHistoryStore)
                                if (!appStore.searchHistoryStore.contains(input)) {//把不存在的记录保存到集合中
                                    searchHistorySet.add(input)
                                }
                                appStore.searchHistoryStore = searchHistorySet
                                updateHistoryUi()

                                Innertube.moSearchPage(SearchBody(query = input))?.onSuccess { result ->
                                    showResultContent()
                                    for (dataPage: Innertube.SearchDataPage in result) {
                                        LogTag.LogD(TAG,"moSearchPage dataPage->$dataPage")
                                        if (dataPage.type == 1) {//type为1的是最佳结果。
                                            binding.contentLayout.addView(
                                                SearchResultOptimalView(requireActivity(), dataPage)
                                            )
                                        } else if (dataPage.type == 2) {//type为2的是其他搜索结果。
                                            if (dataPage.searchResultList.isNotEmpty()) {//如何数据集合为空就不添加view
                                                binding.contentLayout.addView(
                                                    SearchResultOtherView(
                                                        requireActivity(),
                                                        dataPage
                                                    )
                                                )
                                            }
                                        }
                                    }
                                }?.onFailure {
                                    showNoContentLayout()
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)
        if (!hidden) {
            binding.searchEdit.requestFocus()
        } else {
            binding.searchEdit.clearFocus()
            binding.searchEdit.text.clear()
            binding.contentLayout.removeAllViews()
        }
    }

    override fun onHistoryItemClick(position: Int) {
        binding.searchEdit.setText(searchHistory[position])
        requests.trySend(Request.SearchData(searchHistory[position]))
    }

    override fun onItemClick(position: Int) {
        binding.searchEdit.setText(searchSuggestionsList[position])
        requests.trySend(Request.SearchData(searchSuggestionsList[position]))
    }

    override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
        if (actionId == EditorInfo.IME_ACTION_SEARCH) {
            requests.trySend(Request.SearchData(binding.searchEdit.text.toString().trim()))
            return true
        }
        return false
    }

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

    @SuppressLint("NotifyDataSetChanged")
    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        if (s.isNullOrEmpty()) {//没有输入内容，隐藏删除按钮，展示历史记录，重新获取焦点弹出键盘。
            binding.deleteInputBtn.visibility = View.GONE
            showSearchHistory()
            updateHistoryUi()
            binding.searchEdit.requestFocus()
        } else {
            binding.deleteInputBtn.visibility = View.VISIBLE
        }
    }

    override fun afterTextChanged(s: Editable?) {
        requests.trySend(Request.SearchSuggestions)
    }

    override fun onFocusChange(v: View?, hasFocus: Boolean) {
        if (hasFocus) {
            Handler(Looper.getMainLooper()).postDelayed({
                showImm()
            }, 200)
        } else {
            Handler(Looper.getMainLooper()).postDelayed({
                hideImm()
            }, 200)
        }
    }

    private fun showImm() {
        val imm =
            requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.showSoftInput(binding.searchEdit, InputMethodManager.SHOW_IMPLICIT)
    }

    private fun hideImm() {
        val imm =
            requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.hideSoftInputFromWindow(binding.searchEdit.windowToken, 0)
    }

    private fun showResultContent() {
        binding.contentScrollView.visibility = View.VISIBLE
        binding.searchSuggestionsLayout.visibility = View.GONE
        binding.historyLayout.visibility = View.GONE
        binding.loadingLayout.visibility = View.GONE
        binding.noContentLayout.visibility = View.GONE
    }

    private fun showSearchSuggestions() {
        binding.contentScrollView.visibility = View.GONE
        binding.searchSuggestionsLayout.visibility = View.VISIBLE
        binding.historyLayout.visibility = View.GONE
        binding.loadingLayout.visibility = View.GONE
        binding.noContentLayout.visibility = View.GONE
    }

    private fun showSearchHistory() {
        binding.contentScrollView.visibility = View.GONE
        binding.searchSuggestionsLayout.visibility = View.GONE
        binding.historyLayout.visibility = View.VISIBLE
        binding.loadingLayout.visibility = View.GONE
        binding.noContentLayout.visibility = View.GONE
    }

    private fun showLoadingLayout() {
        binding.loadingLayout.visibility = View.VISIBLE
        binding.noContentLayout.visibility = View.GONE
        binding.contentScrollView.visibility = View.GONE
        binding.searchSuggestionsLayout.visibility = View.GONE
        binding.historyLayout.visibility = View.GONE
    }

    private fun showNoContentLayout() {
        binding.loadingLayout.visibility = View.GONE
        binding.noContentLayout.visibility = View.VISIBLE
        binding.contentScrollView.visibility = View.GONE
        binding.searchSuggestionsLayout.visibility = View.GONE
        binding.historyLayout.visibility = View.GONE
    }

}