package com.gh.gamecenter

import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import com.gh.common.fragment.popBackStackAllowStateLoss
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.LogUtils
import com.gh.gamecenter.DisplayType.*
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.TextHelper
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.db.SearchHistoryDao
import com.gh.gamecenter.eventbus.EBSearch
import com.gh.gamecenter.search.SearchDefaultFragment
import com.gh.gamecenter.search.SearchGameIndexFragment
import com.gh.gamecenter.search.SearchGameResultFragment
import com.gh.gamecenter.search.SearchTabActivity
import com.lightgame.utils.Util_System_Keyboard
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.subjects.PublishSubject
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.concurrent.TimeUnit

/**
 * 游戏搜索页
 */
open class SearchActivity : BaseActivity() {

    lateinit var searchEt: EditText
    lateinit var searchBtn: TextView
    lateinit var backBtn: RelativeLayout
    private lateinit var deleteIv: ImageView

    val mDao: ISearchHistoryDao by lazy { provideDao() }

    protected var mSearchKey: String? = null
    protected var mIsAutoSearchDisabled: Boolean = false

    protected var mSearchType = SearchType.DEFAULT
    protected var mDisplayType = DEFAULT

    private var mPublishSubject: PublishSubject<String>? = null

    /**
     * 神策的 SourceEntrance 字段相当于 火山云的 location
     * 如果有火山云埋点需要上传 location 字段，那么直接使用此字段的值就行
     */
    protected var mSourceEntrance: String = ""

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putInt(KEY_DISPLAY_TYPE, mDisplayType.value)
        outState.putString(EntranceConsts.KEY_SEARCHKEY, mSearchKey)
        outState.putString(KEY_SEARCH_TYPE, mSearchType.value)
    }

    override fun getLayoutId(): Int {
        return R.layout.activity_search
    }

    @SuppressLint("CheckResult")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        updateStatusBarColor(com.gh.gamecenter.common.R.color.ui_surface, com.gh.gamecenter.common.R.color.ui_surface)

        searchEt = findViewById(R.id.searchEt)
        searchBtn = findViewById(com.gh.gamecenter.common.R.id.searchBtn)
        deleteIv = findViewById(R.id.deleteIv)
        backBtn = findViewById(R.id.backBtn)

        mSourceEntrance = intent.getStringExtra(EntranceConsts.KEY_SOURCE_ENTRANCE) ?: ""
        val hint = intent.getStringExtra(EntranceConsts.KEY_HINT)
        val searchImmediately = intent.getBooleanExtra(KEY_SEARCH_IMMEDIATELY, false)

        mPublishSubject = PublishSubject.create()

        mPublishSubject!!
            .debounce(300, TimeUnit.MILLISECONDS)
            .distinctUntilChanged()
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                if (searchEt.text.isNotEmpty()
                    && searchEt.text != searchEt.hint
                ) {
                    search(SearchType.AUTO, it)
                }
            }

        initSearchBar()

        if (!TextUtils.isEmpty(hint)) {
            searchEt.hint = hint
            if (searchImmediately) {
                mDisplayType = GAME_DETAIL
                mDao.add(hint)
                search(SearchType.DEFAULT, hint)
            }
        } else {
            searchEt.hint = HINT_TEXT
        }

        if (savedInstanceState == null
            && mDisplayType == DEFAULT
        ) {
            updateDisplayType(DEFAULT)
        }

        val bottomTab = intent.getStringExtra(EntranceConsts.KEY_BOTTOM_TAB_NAME) ?: ""
        val multiTabId = intent.getStringExtra(EntranceConsts.KEY_MULTI_TAB_NAV_ID) ?: ""
        val multiTabName = intent.getStringExtra(EntranceConsts.KEY_MULTI_TAB_NAV_NAME) ?: ""
        val customPageId = intent.getStringExtra(EntranceConsts.KEY_CUSTOM_PAGE_ID) ?: ""
        val customPageName = intent.getStringExtra(EntranceConsts.KEY_CUSTOM_PAGE_NAME) ?: ""
        val searchBoxPattern = intent.getStringExtra(EntranceConsts.KEY_SEARCH_BOX_PATTERN) ?: ""
        SensorsBridge.trackGameSearchPageShow(
            GlobalActivityManager.getCurrentPageEntity().pageId,
            GlobalActivityManager.getCurrentPageEntity().pageName,
            mSourceEntrance,
            bottomTab,
            multiTabId,
            multiTabName,
            customPageId,
            customPageName,
            searchBoxPattern
        )
    }

    open fun initSearchBar() {
        // 进入获取焦点
        searchEt.post { searchEt.requestFocus() }

        searchEt.setOnEditorActionListener { _, actionId, _ ->
            if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                Util_System_Keyboard.hideSoftKeyboard(this)
                search(SearchType.MANUAL, null)
            }
            false
        }

        searchBtn.setOnClickListener {
            Util_System_Keyboard.hideSoftKeyboard(this)
            search(SearchType.MANUAL, null)
        }

        deleteIv.setOnClickListener {
            deleteIv.visibility = View.GONE
            searchEt.setText("")
        }

        searchEt.doOnTextChanged { text, _, _, _ -> deleteIv.goneIf(text?.length == 0) }
        searchEt.doAfterTextChanged { editable ->
            val newSearchKey = editable.toString().trim { it <= ' ' }
            if (newSearchKey.isEmpty()) {
                handleEmptySearch(newSearchKey)
            } else if (!mIsAutoSearchDisabled) {
                mPublishSubject?.onNext(newSearchKey)
            }
        }
        searchEt.filters = arrayOf(TextHelper.getFilter(50, "最多输入50个字"))

        backBtn.setOnClickListener { onBackPressed() }
    }

    open fun search(type: SearchType, key: String?) {
        mSearchType = type
        mIsAutoSearchDisabled = true
        // 自动搜索，默认搜索，热门搜索，历史搜索，主动搜索，榜单搜索
        when (type) {
            SearchType.AUTO -> handleAutoSearch(key)
            SearchType.DEFAULT -> handleDefaultSearch(key)
            SearchType.DISCOVERY -> handleDiscoverySearch(key)
            SearchType.RANK -> handleRankSearch(key)
            SearchType.HOT -> handleHotSearch(key)
            SearchType.HISTORY -> handleHistorySearch(key)
            SearchType.MANUAL -> handleManualSearch()
        }
        mIsAutoSearchDisabled = false
    }

    protected open fun handleEmptySearch(newSearchKey: String) {
        popBackToFragment(SearchDefaultFragment::class.java.name)// 回退到搜索首页
        mPublishSubject?.onNext(newSearchKey)
    }

    protected open fun handleAutoSearch(key: String?) {
        val newSearchKey = searchEt.text.toString().trim { it <= ' ' }
        if (newSearchKey.isEmpty()) {
            val hint = searchEt.hint.toString()
            if (!TextUtils.isEmpty(hint) && HINT_TEXT != hint) {
                mDao.add(hint)
                search(SearchType.DEFAULT, hint)
            }
        } else {
            mSearchKey = key
            updateDisplayType(GAME_DIGEST)
            LogUtils.uploadSearchGame("searching", "搜索页", key, "自动搜索")

            SensorsBridge.trackGameSearchPageButtonClick(
                GlobalActivityManager.getCurrentPageEntity().pageId,
                GlobalActivityManager.getCurrentPageEntity().pageName,
                mSourceEntrance,
                key ?: "",
                TRACK_SEARCH_TYPE_AUTO
            )
        }
    }

    protected open fun handleRankSearch(key: String?) {
        mSearchKey = key
        searchEt.setText(key)
        searchEt.setSelection(searchEt.text.length)
        updateDisplayType(GAME_DETAIL)
        LogUtils.uploadSearchGame("searching", "搜索页", key, "榜单搜索")

        SensorsBridge.trackSearchButtonClick(
            GlobalActivityManager.getCurrentPageEntity().pageId,
            GlobalActivityManager.getCurrentPageEntity().pageName,
            key ?: "",
            TRACK_SEARCH_TYPE_RANK,
            mSourceEntrance
        )
    }

    protected open fun handleDiscoverySearch(key: String?) {
        mSearchKey = key
        searchEt.setText(key)
        searchEt.setSelection(searchEt.text.length)
        updateDisplayType(GAME_DETAIL)
        LogUtils.uploadSearchGame("searching", "搜索页", key, "搜索发现")

        SensorsBridge.trackSearchButtonClick(
            GlobalActivityManager.getCurrentPageEntity().pageId,
            GlobalActivityManager.getCurrentPageEntity().pageName,
            key ?: "",
            TRACK_SEARCH_TYPE_DISCOVERY,
            mSourceEntrance
        )
    }

    protected open fun handleDefaultSearch(key: String?) {
        mSearchKey = key
        searchEt.setText(key)
        searchEt.setSelection(searchEt.text.length)
        updateDisplayType(GAME_DETAIL)
        LogUtils.uploadSearchGame("searching", "搜索页", key, "默认搜索")

        SensorsBridge.trackGameSearchPageButtonClick(
            GlobalActivityManager.getCurrentPageEntity().pageId,
            GlobalActivityManager.getCurrentPageEntity().pageName,
            mSourceEntrance,
            key ?: "",
            TRACK_SEARCH_TYPE_DEFAULT
        )
    }

    protected open fun handleHotSearch(key: String?) {
        mSearchKey = key
        searchEt.setText(key)
        searchEt.setSelection(searchEt.text.length)
        updateDisplayType(GAME_DETAIL)
    }

    protected open fun handleHistorySearch(key: String?) {
        mSearchKey = key
        searchEt.setText(key)
        searchEt.setSelection(searchEt.text.length)
        updateDisplayType(GAME_DETAIL)
        LogUtils.uploadSearchGame("searching", "搜索页", key, "历史搜索")

        SensorsBridge.trackGameSearchPageButtonClick(
            GlobalActivityManager.getCurrentPageEntity().pageId,
            GlobalActivityManager.getCurrentPageEntity().pageName,
            mSourceEntrance,
            key ?: "",
            TRACK_SEARCH_TYPE_HISTORY
        )
    }

    protected open fun handleManualSearch() {
        val newSearchKey = searchEt.text.toString().trim { it <= ' ' }
        if (newSearchKey.isEmpty()) {
            val hint = searchEt.hint.toString()
            if (!TextUtils.isEmpty(hint) && HINT_TEXT != hint) {
                mDao.add(hint)
                search(SearchType.DEFAULT, hint)
            }
        } else if (newSearchKey != mSearchKey || mDisplayType != GAME_DETAIL) {
            mSearchKey = newSearchKey
            if (!TextUtils.isEmpty(mSearchKey)) {
                mDao.add(mSearchKey)
                updateDisplayType(GAME_DETAIL)

                SensorsBridge.trackGameSearchPageButtonClick(
                    GlobalActivityManager.getCurrentPageEntity().pageId,
                    GlobalActivityManager.getCurrentPageEntity().pageName,
                    mSourceEntrance,
                    newSearchKey,
                    TRACK_SEARCH_TYPE_INPUT
                )
            } else {
                toast("请输入搜索内容")
            }
        }
        LogUtils.uploadSearchGame("searching", "搜索页", newSearchKey, "主动搜索")
//        MtaHelper.onEvent("游戏搜索", "主动搜索", newSearchKey)
    }

    override fun onResume() {
        super.onResume()
        val newSearchKey = searchEt.text.toString().trim { it <= ' ' }
        if (newSearchKey.isBlank()) {
            try {
                popBackToFragment(SearchDefaultFragment::class.java.name)
            } catch (e: Exception) {
                // no implement
            }

        }
    }

    protected open fun provideDao(): ISearchHistoryDao = SearchHistoryDao(this)

    open fun updateDisplayType(type: DisplayType) {
        val transaction = when (type) {
            DEFAULT -> showFragment(
                SearchDefaultFragment::class.java.name,
                { SearchDefaultFragment() }
            ) {
                it.arguments = Bundle().also { bundle ->
                    bundle.putBoolean(SearchDefaultFragment.KEY_IS_GAME_SEARCH, true)
                }
            }

            GAME_DIGEST -> showFragment(
                SearchGameIndexFragment::class.java.name,
                { SearchGameIndexFragment() }
            ) {
                removeFragment(SearchGameResultFragment::class.java.name)
                it.setParams(mSearchKey ?: "", mSearchType.value)
            }

            GAME_DETAIL -> showFragment(
                SearchGameResultFragment::class.java.name,
                { SearchGameResultFragment() }
            ) {
                removeFragment(SearchGameIndexFragment::class.java.name)
                it.setParams(mSearchKey ?: "", mSearchType.value)
            }

            else -> null
        }
        mDisplayType = type
        transaction?.commitAllowingStateLoss()
    }

    protected fun <T : Fragment> showFragment(
        tag: String,
        onFragmentCreate: () -> T,
        onFragmentCreated: ((T) -> Unit)? = null,
    ): FragmentTransaction {
        val transaction = supportFragmentManager.beginTransaction()
        var createNewFragment = false
        var fragment = supportFragmentManager
            .findFragmentByTag(tag)
        if (fragment == null) {
            createNewFragment = true
            fragment = onFragmentCreate.invoke()
        }
        onFragmentCreated?.invoke(fragment as T)
        if (createNewFragment) {
            transaction.add(R.id.search_result, fragment, tag)
            transaction.addToBackStack(tag)
        } else if (!fragment.isAdded) {
            transaction.show(fragment)
            transaction.addToBackStack(tag)
        }
        return transaction
    }

    protected fun removeFragment(tag: String) {
        val fragment = supportFragmentManager
            .findFragmentByTag(tag) ?: return
        supportFragmentManager
            .beginTransaction()
            .remove(fragment)
            .commit()
        supportFragmentManager.popBackStack()
    }

    protected fun popBackToFragment(tag: String) {
        supportFragmentManager.popBackStackAllowStateLoss(tag, 0)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEvent(search: EBSearch) {
        when (search.type) {
            SearchType.HISTORY.value -> search(SearchType.HISTORY, search.key)
            SearchType.HOT.value -> search(SearchType.HOT, search.key)
            SearchType.RANK.value -> search(SearchType.RANK, search.key)
            SearchType.DISCOVERY.value -> search(SearchType.DISCOVERY, search.key)

            "click" -> DataCollectionUtils.uploadSearchClick(
                this, mSearchKey, mSearchType.value, "搜索页面",
                search.gameId, search.gameName
            )

            "search" -> {
                DataCollectionUtils.uploadSearch(
                    this, mSearchKey, mSearchType.value, "搜索页面",
                    search.gameId, search.gameName
                )
            }
        }
    }

    override fun handleBackPressed(): Boolean {
        if (supportFragmentManager.fragments.size == 1) {
            finish()
            return true
        }
        if (supportFragmentManager.fragments.size > 1) {
            mDisplayType = DEFAULT
        }
        return super.handleBackPressed()
    }

    override fun onDarkModeChanged() {
        super.onDarkModeChanged()
        updateStatusBarColor(com.gh.gamecenter.common.R.color.ui_surface, com.gh.gamecenter.common.R.color.ui_surface)
    }

    override fun isAutoResetViewBackgroundEnabled() = true

    companion object {
        const val KEY_SEARCH_TYPE = "search_type"
        private const val KEY_DISPLAY_TYPE = "display_type"
        private const val KEY_SEARCH_IMMEDIATELY = "search_immediately"
        private const val HINT_TEXT = "搜索游戏..."

        const val TRACK_SEARCH_TYPE_AUTO = "自动搜索"
        const val TRACK_SEARCH_TYPE_INPUT = "输入搜索"
        const val TRACK_SEARCH_TYPE_DEFAULT = "默认搜索"
        const val TRACK_SEARCH_TYPE_HISTORY = "历史搜索"
        const val TRACK_SEARCH_TYPE_RANK = "榜单搜索"
        const val TRACK_SEARCH_TYPE_DISCOVERY = "搜索发现"

        @JvmStatic
        fun toTrackSearchType(type: String) = when (type) {
            SearchType.AUTO.value -> TRACK_SEARCH_TYPE_AUTO
            SearchType.MANUAL.value -> TRACK_SEARCH_TYPE_INPUT
            SearchType.HISTORY.value -> TRACK_SEARCH_TYPE_HISTORY
            SearchType.RANK.value -> TRACK_SEARCH_TYPE_RANK
            SearchType.DISCOVERY.value -> TRACK_SEARCH_TYPE_DISCOVERY
            else -> TRACK_SEARCH_TYPE_DEFAULT
        }

        @JvmStatic
        fun getIntent(
            context: Context,
            searchImmediately: Boolean,
            hint: String,
            entrance: String,
            sourceEntrance: String
        ): Intent =
            getIntent(context, searchImmediately, hint, entrance, sourceEntrance, "", "", "", "", "", "")

        @JvmStatic
        fun getIntent(
            context: Context,
            searchImmediately: Boolean,
            hint: String,
            entrance: String,
            sourceEntrance: String,
            bottomTab: String = "",
            multiTabId: String = "",
            multiTabName: String = "",
            customPageId: String = "",
            customPageName: String = "",
            searchBoxPattern: String = ""
        ): Intent {
            val intent = Intent(context, SearchTabActivity::class.java)
            intent.putExtra(KEY_SEARCH_IMMEDIATELY, searchImmediately)
            intent.putExtra(EntranceConsts.KEY_HINT, hint)
            intent.putExtra(EntranceConsts.KEY_ENTRANCE, entrance)
            intent.putExtra(EntranceConsts.KEY_SOURCE_ENTRANCE, sourceEntrance)
            intent.putExtra(EntranceConsts.KEY_BOTTOM_TAB_NAME, bottomTab)
            intent.putExtra(EntranceConsts.KEY_MULTI_TAB_NAV_ID, multiTabId)
            intent.putExtra(EntranceConsts.KEY_MULTI_TAB_NAV_NAME, multiTabName)
            intent.putExtra(EntranceConsts.KEY_CUSTOM_PAGE_ID, customPageId)
            intent.putExtra(EntranceConsts.KEY_CUSTOM_PAGE_NAME, customPageName)
            intent.putExtra(EntranceConsts.KEY_SEARCH_BOX_PATTERN, searchBoxPattern)
            return intent
        }
    }
}

enum class SearchType(var value: String) {
    AUTO("auto"),
    DEFAULT("default"),
    HISTORY("history"),
    MANUAL("initiative"),
    HOT("remen"),
    RANK("rank"),
    DISCOVERY("dicovery");

    fun toChinese() = when (this) {
        AUTO -> "自动搜索"
        DEFAULT -> "默认搜索"
        HISTORY -> "历史搜索"
        MANUAL -> "主动搜索"
        HOT -> "热门搜索"
        RANK -> "榜单搜索"
        DISCOVERY -> "搜索发现"
    }

    companion object {
        @JvmStatic
        fun fromString(typeString: String) = values().find { typeString == it.value } ?: DEFAULT
    }
}

/**
 *
 * [DEFAULT] 默认搜索页
 * [GAME_DIGEST] 游戏为部分文字样式的列表
 * [GAME_DETAIL] 游戏全为标准样式的列表
 * [FORUM_OR_USER] 论坛内容和用户
 */
enum class DisplayType(var value: Int) {
    DEFAULT(0),
    GAME_DIGEST(1),
    GAME_DETAIL(2),
    FORUM_OR_USER(3);
}
