package com.videoapp.tv.ui import android.content.Intent import android.os.Bundle import android.view.KeyEvent import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.inputmethod.EditorInfo import android.webkit.WebView import android.webkit.WebViewClient import android.widget.Button import android.widget.EditText import android.widget.TextView import android.widget.Toast import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import com.videoapp.tv.R import com.videoapp.tv.PlayerActivity import com.videoapp.tv.SettingsActivity import com.videoapp.tv.data.AppDatabase import com.videoapp.tv.data.SearchHistory import com.videoapp.tv.data.SearchResult import com.videoapp.tv.engine.SearchCoordinator import kotlinx.coroutines.launch class SearchFragment : Fragment() { private lateinit var searchInput: EditText private lateinit var btnSearch: Button private lateinit var btnSettings: Button private lateinit var historyContainer: ViewGroup private lateinit var historyList: ViewGroup private lateinit var btnClearHistory: Button private lateinit var resultsGrid: RecyclerView private lateinit var loadingProgress: View private lateinit var statusText: TextView private lateinit var fallbackWebView: WebView private val searchCoordinator by lazy { SearchCoordinator(requireContext()) } private val historyDao by lazy { AppDatabase.getInstance(requireContext()).searchHistoryDao() } private val adapter by lazy { SearchResultAdapter( onItemClick = { result -> openPlayer(result) }, onItemFocus = { view -> view.animate().scaleX(1.05f).scaleY(1.05f).setDuration(150).start() } ) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.fragment_search, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) searchInput = view.findViewById(R.id.search_input) btnSearch = view.findViewById(R.id.btn_search) btnSettings = view.findViewById(R.id.btn_settings) historyContainer = view.findViewById(R.id.history_container) historyList = view.findViewById(R.id.history_list) btnClearHistory = view.findViewById(R.id.btn_clear_history) resultsGrid = view.findViewById(R.id.results_grid) loadingProgress = view.findViewById(R.id.loading_progress) statusText = view.findViewById(R.id.status_text) fallbackWebView = view.findViewById(R.id.fallback_webview) setupResultsGrid() setupListeners() loadHistory() } private fun setupResultsGrid() { val spanCount = if (resources.configuration.screenWidthDp >= 600) 5 else 3 resultsGrid.layoutManager = GridLayoutManager(context, spanCount) resultsGrid.adapter = adapter } private fun setupListeners() { searchInput.setOnEditorActionListener { _, actionId, event -> if (actionId == EditorInfo.IME_ACTION_SEARCH || (event?.keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN) ) { performSearch(searchInput.text.toString().trim()) true } else { false } } btnSearch.setOnClickListener { performSearch(searchInput.text.toString().trim()) } btnSettings.setOnClickListener { startActivity(Intent(requireContext(), SettingsActivity::class.java)) } btnClearHistory.setOnClickListener { lifecycleScope.launch { historyDao.clearAll() showHistory(emptyList()) } } } private fun performSearch(keyword: String) { if (keyword.isEmpty()) return hideFallbackWebView() showLoading(true) statusText.visibility = View.GONE historyContainer.visibility = View.GONE lifecycleScope.launch { // Save to history val existing = historyDao.findByKeyword(keyword) if (existing != null) { historyDao.updateTime(existing.id, System.currentTimeMillis()) } else { historyDao.insert(SearchHistory(keyword = keyword)) } } lifecycleScope.launch { searchCoordinator.search( keyword = keyword, onResult = { results -> showLoading(false) adapter.setItems(results) if (results.isEmpty()) { showStatus("未找到结果") } }, onError = { error -> showLoading(false) if (error == "FALLBACK_WEBVIEW") { showFallbackWebView(keyword) } else { showStatus("搜索失败,请重试") Toast.makeText(requireContext(), error, Toast.LENGTH_LONG).show() } }, onFallbackToWebView = { showFallbackWebView(keyword) } ) } } private fun showFallbackWebView(keyword: String) { val config = searchCoordinator.getConfig() val base = config.baseUrl.trimEnd('/') val path = config.searchPath.trimStart('/') val params = "${config.keywordParam}=${java.net.URLEncoder.encode(keyword, "UTF-8")}" val extraParams = config.extraParams.entries.joinToString("&") { "${it.key}=${it.value}" } val url = "$base/$path?$params&$extraParams" fallbackWebView.visibility = View.VISIBLE resultsGrid.visibility = View.GONE fallbackWebView.settings.javaScriptEnabled = true fallbackWebView.webViewClient = WebViewClient() fallbackWebView.loadUrl(url) } private fun hideFallbackWebView() { fallbackWebView.visibility = View.GONE fallbackWebView.stopLoading() resultsGrid.visibility = View.VISIBLE } private fun showLoading(show: Boolean) { loadingProgress.visibility = if (show) View.VISIBLE else View.GONE } private fun showStatus(msg: String) { statusText.text = msg statusText.visibility = View.VISIBLE } private fun openPlayer(result: SearchResult) { val intent = Intent(requireContext(), PlayerActivity::class.java).apply { putExtra("detail_url", result.detailUrl) putExtra("title", result.title) putExtra("category", result.category) } startActivity(intent) } private fun loadHistory() { lifecycleScope.launch { historyDao.getRecentHistory().collect { list -> showHistory(list) } } } private fun showHistory(list: List) { historyList.removeAllViews() if (list.isEmpty()) { historyContainer.visibility = View.GONE return } for (item in list) { val chip = Button(requireContext()).apply { text = item.keyword setTextColor(ContextCompat.getColor(requireContext(), R.color.text_primary)) setBackgroundResource(R.drawable.history_chip_selector) textSize = 14f setPadding(24, 8, 24, 8) isFocusable = true isFocusableInTouchMode = true setOnClickListener { searchInput.setText(item.keyword) performSearch(item.keyword) } } historyList.addView(chip) } } override fun onDestroyView() { super.onDestroyView() fallbackWebView.destroy() } }