package com.all.pdfreader.pro.app.ui.act

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import androidx.activity.OnBackPressedCallback
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.all.pdfreader.pro.app.R
import com.all.pdfreader.pro.app.databinding.ActivityPdfViewBinding
import com.all.pdfreader.pro.app.model.FileActionEvent
import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity
import com.all.pdfreader.pro.app.ui.dialog.BookmarksDialogFragment
import com.all.pdfreader.pro.app.ui.dialog.ListMoreDialogFragment
import com.all.pdfreader.pro.app.ui.dialog.PdfPasswordProtectionDialogFragment
import com.all.pdfreader.pro.app.ui.dialog.ViewModelDialogFragment
import com.all.pdfreader.pro.app.ui.view.CustomScrollHandle
import com.all.pdfreader.pro.app.util.AppUtils
import com.all.pdfreader.pro.app.util.AppUtils.hideKeyboard
import com.all.pdfreader.pro.app.util.AppUtils.showKeyboard
import com.all.pdfreader.pro.app.util.FileUtils
import com.all.pdfreader.pro.app.util.PDFHighlighter
import com.all.pdfreader.pro.app.util.PDFSearchManager
import com.all.pdfreader.pro.app.viewmodel.PdfViewModel
import com.all.pdfreader.pro.app.viewmodel.observeEvent
import com.github.barteksc.pdfviewer.listener.OnErrorListener
import com.github.barteksc.pdfviewer.listener.OnLoadCompleteListener
import com.github.barteksc.pdfviewer.listener.OnPageChangeListener
import com.github.barteksc.pdfviewer.listener.OnTapListener
import com.tom_roush.pdfbox.pdmodel.PDDocument
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File

class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeListener,
    OnErrorListener, OnTapListener {
    override val TAG: String = "PdfViewActivity"

    companion object {
        const val FRAG_TAG = "PdfViewActivity"
        private const val EXTRA_PDF_HASH = "extra_pdf_hash"

        // 创建启动Intent的便捷方法
        fun createIntent(context: Context, filePath: String): Intent {
            return Intent(context, PdfViewActivity::class.java).apply {
                putExtra(EXTRA_PDF_HASH, filePath)
            }
        }
    }

    private lateinit var binding: ActivityPdfViewBinding
    private lateinit var pdfDocument: PdfDocumentEntity
    private val viewModel by lazy { ViewModelProvider(this)[PdfViewModel::class.java] }
    private val repository = getRepository()
    private var isFullScreen = false
    private var lastLoadedFilePath: String? = null
    private var showSearchTextView = false
    private lateinit var searchManager: PDFSearchManager
    private lateinit var highlighter: PDFHighlighter
    private var pageCheckJob: Job? = null
    private var currentPassword: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityPdfViewBinding.inflate(layoutInflater)
        setContentView(binding.root)
        setupDoubleBackExit()
        initObserve()
        val filePath = intent.getStringExtra(EXTRA_PDF_HASH)
            ?: throw IllegalArgumentException("PDF file hash is required")
        // 加载PDF数据
        viewModel.getPDFDocument(filePath)
        //加载书签数据
        viewModel.getBookmarks(filePath)
        setupOnClick()
    }

    private fun initObserve() {
        // 观察PDF文档数据
        viewModel.pdfDocument.observe(this) { document ->
            document?.let {
                pdfDocument = it
                if (lastLoadedFilePath != pdfDocument.filePath) {
                    lastLoadedFilePath = pdfDocument.filePath
                    loadPdf()
                }
                initView()
            } ?: run {
                showToast(getString(R.string.file_not))
                finish()
            }
        }
        //观察书签数据
        viewModel.pdfBookmark.observe(this) { list ->
            logDebug("observe->bookmarks: ${list.size}")
            list?.let {
                binding.bookmarksHint.text = "${it.size}"
                if (it.isEmpty()) {
                    binding.bookmarksHint.visibility = View.GONE
                } else {
                    binding.bookmarksHint.visibility = View.VISIBLE
                }
            } ?: run {
                binding.bookmarksHint.visibility = View.GONE
            }
        }

        viewModel.fileActionEvent.observeEvent<FileActionEvent.AddBookmark>(this) {
            if (it.success) {
                showToast(getString(R.string.bookmark_add_success))
            } else {
                showToast(getString(R.string.bookmark_add_fail))
            }
        }
        viewModel.fileActionEvent.observeEvent<FileActionEvent.Rename>(this) { event ->
            if (event.renameResult.success) {
                showToast(getString(R.string.rename_successfully))
                event.renameResult.newFilePath?.let {
                    viewModel.getPDFDocument(it)//修改成功后更新当前页面的数据
                    viewModel.getBookmarks(it)
                }
            } else {
                showToast(event.renameResult.errorMessage.toString())
            }
        }
        viewModel.fileActionEvent.observeEvent<FileActionEvent.Duplicate>(this) { event ->
            if (event.file != null) {
                showToast(getString(R.string.duplicate_created_successfully))
            } else {
                showToast(getString(R.string.duplicate_created_failed))
            }
        }
        viewModel.fileActionEvent.observeEvent<FileActionEvent.Favorite>(this) { event ->
            if (event.isFavorite) {
                showToast(getString(R.string.added_to_favorites))
            } else {
                showToast(getString(R.string.removed_from_favorites))
            }
        }

        viewModel.fileActionEvent.observeEvent<FileActionEvent.SetPageFling>(this) { event ->
            val file = File(pdfDocument.filePath)
            loadPdfInternal(file, currentPassword)
        }

        viewModel.fileActionEvent.observeEvent<FileActionEvent.SetColorInversion>(this) { event ->
            binding.pdfview.apply {
                setNightMode(event.b)
                loadPages()
                if (event.b) {
                    setBackgroundColor(getColor(R.color.night_mode_bg_color))
                } else {
                    setBackgroundColor(getColor(R.color.grey))
                }
            }
        }
        viewModel.fileActionEvent.observeEvent<FileActionEvent.SetSwipeVertical>(this) { event ->
            val file = File(pdfDocument.filePath)
            loadPdfInternal(file, currentPassword)
        }
        viewModel.fileActionEvent.observeEvent<FileActionEvent.GotoPage>(this) { event ->
            binding.pdfview.apply {
                jumpTo(event.number - 1)
            }
        }
    }

    private fun initView() {
        binding.title.text = FileUtils.removeFileExtension(pdfDocument.fileName)
        toggleEyeCareMode(appStore.isEyeCareMode)
    }

    private fun setupOnClick() {
        binding.backBtn.setOnClickListener {
            onBackPressedDispatcher.onBackPressed()
        }
        binding.eyeCareOverlayBtn.setOnClickListener {
            appStore.isEyeCareMode = !appStore.isEyeCareMode
            toggleEyeCareMode(appStore.isEyeCareMode)
        }
        binding.viewModelBtn.setOnClickListener {
            ViewModelDialogFragment().show(supportFragmentManager, "ViewModelDialogFragment")
        }
        binding.bookmarksBtn.setOnClickListener {
            BookmarksDialogFragment(pdfDocument, onJumpPage = {
                binding.pdfview.jumpTo(it)
                binding.pdfview.postDelayed({
                    binding.pdfview.resetZoomWithAnimation()
                }, 200)
            }).show(supportFragmentManager, "BookmarksDialogFragment")
        }
        binding.shareBtn.setOnClickListener {
            AppUtils.shareFile(this, File(pdfDocument.filePath))
        }
        binding.moreBtn.setOnClickListener {
            ListMoreDialogFragment(pdfDocument.filePath).show(supportFragmentManager, FRAG_TAG)
        }
        binding.searchTextBtn.setOnClickListener {
            showSearchTextView = true
            updateSearchState(true)
            binding.selectNextBtn.visibility = View.GONE
            binding.selectPreviousBtn.visibility = View.GONE
        }
        binding.searchEdit.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
            override fun afterTextChanged(s: Editable?) {
                val query = s?.toString().orEmpty()
                binding.deleteIv.visibility = if (query.isEmpty()) View.GONE else View.VISIBLE
                binding.searchIv.visibility = if (query.isEmpty()) View.VISIBLE else View.GONE
            }
        })
        binding.searchEdit.setOnEditorActionListener { _, actionId, _ ->
            if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                val searchText = binding.searchEdit.text.toString().trim()
                if (searchText.isNotEmpty()) {
                    performSearch(searchText)
                    binding.searchEdit.hideKeyboard()  // 收起键盘
                } else {
                    showToast(getString(R.string.enter_search_key))
                }
                true
            } else {
                false
            }
        }
        binding.deleteIv.setOnClickListener {
            binding.searchEdit.apply {
                setText("")
                clearComposingText()
                setSelection(0)
            }
            clearHighlights()
            binding.selectNextBtn.visibility = View.GONE
            binding.selectPreviousBtn.visibility = View.GONE
        }
        binding.selectNextBtn.setOnClickListener {
            highlighter.selectNext { id ->
                showToast(getString(id))
            }
        }
        binding.selectPreviousBtn.setOnClickListener {
            highlighter.selectPrevious { id ->
                showToast(getString(id))
            }
        }
    }

    private fun loadPdf() {
        logDebug("loadPdf ->${pdfDocument.lastReadPage} ${pdfDocument.readingProgress}")
        // 使用传递的文件路径加载PDF
        val file = File(pdfDocument.filePath)
        if (!file.exists()) {
            showToast(getString(R.string.file_not) + ": ${pdfDocument.fileName}")
            finish()
            return
        }
        if (pdfDocument.isPassword) {
            showPasswordDialog(file)
        } else {
            loadPdfInternal(file, null) // 无密码
        }
    }

    //PDF 文档加载完成时回调
    override fun loadComplete(nbPages: Int) {
        binding.pdfview.post {
            binding.pdfview.resetZoom() // 不走动画
        }
    }

    //PDF 加载出错时回调
    override fun onError(t: Throwable?) {
        logDebug("PDF loading error: ${t?.message}")
        t?.let {
            val errorMessage = it.message ?: getString(R.string.pdf_loading_failed)
            // 检查是否是密码相关的错误
            if (errorMessage.contains("Password") || errorMessage.contains("password")) {
                val file = File(pdfDocument.filePath)
                showPasswordDialog(file)
            } else {
                showToast(errorMessage)
                finish()
            }
        }
    }

    override fun onTap(e: MotionEvent?): Boolean {
        toggleFullScreen()
        return true// 表示我们自己处理了单击事件
    }

    //页面切换时回调
    override fun onPageChanged(page: Int, pageCount: Int) {
        // 保存阅读进度到内存
        pdfDocument = pdfDocument.copy(
            lastReadPage = page, readingProgress = (page.toFloat() / pageCount.toFloat()) * 100
        )
        saveReadingProgress()

        val doc = searchManager.getCachedDoc() ?: return
        // 取消上一次检查任务
        pageCheckJob?.cancel()
        // 启动新的防抖任务
        pageCheckJob = lifecycleScope.launch(Dispatchers.IO) {
            highlighter.clearCurrentHighlights()//新的之前先清除
            delay(120) // 防抖 120ms
            val hasText = checkPageHasText(doc, page)
            if (hasText && searchManager.hasSearched && !searchManager.currentSearchText.isNullOrEmpty()) {
                searchTextIng(
                    File(pdfDocument.filePath),
                    searchManager.currentSearchText ?: "",
                    binding.pdfview.currentPage
                )
            }
        }
    }

    private fun saveReadingProgress() {
        lifecycleScope.launch {
            repository.updateReadingProgress(
                pdfDocument.filePath, pdfDocument.lastReadPage, pdfDocument.readingProgress
            )
        }
    }

    private fun showPasswordDialog(file: File) {
        PdfPasswordProtectionDialogFragment(file, onOkClick = { password ->
            tryLoadPdfWithPassword(file, password)
        }, onCancelClick = {
            finish()
        }).show(supportFragmentManager, TAG)
    }

    private fun tryLoadPdfWithPassword(file: File, password: String) {
        loadPdfInternal(file, password) // 传入密码
        currentPassword = password
    }

    private fun loadPdfInternal(file: File, password: String?) {
        setupPDFSearchManager(password)//初始化搜索文本需要的类
        binding.pdfview.fromFile(file).apply {
            password?.let { password(it) } // 只有在有密码时才调用
            defaultPage(pdfDocument.lastReadPage) // 从上次阅读页码开始
            enableDoubletap(true) // 是否允许双击缩放
            enableAnnotationRendering(true)  // 是否渲染注释
            onLoad(this@PdfViewActivity) // 加载回调
            onError(this@PdfViewActivity) // 错误回调
            onTap(this@PdfViewActivity) // 单击回调
            onPageChange(this@PdfViewActivity) // 页面改变回调
            scrollHandle(CustomScrollHandle(this@PdfViewActivity)) // 自定义的页数展示
            onDraw(highlighter)
            if (appStore.isPageFling) {
                pageSnap(true)//页面可在逐页中，可居中展示，非逐页模式，滑动停止后可自动定格在居中位置。
                pageFling(true)//逐页
                autoSpacing(true)
            } else {
                pageSnap(false)
                pageFling(false)
                spacing(10)
            }
            swipeHorizontal(!appStore.isVertical)
            nightMode(appStore.isColorInversion)
        }.load()
        if (appStore.isColorInversion) {
            binding.pdfview.setBackgroundColor(getColor(R.color.night_mode_bg_color))
        } else {
            binding.pdfview.setBackgroundColor(getColor(R.color.grey))
        }
    }

    private fun toggleFullScreen() {
        if (showSearchTextView) {//如果是搜索文本时，不全屏
            return
        }
        isFullScreen = !isFullScreen
        updateStatusAndNavigationLayout(isFullScreen)
        if (isFullScreen) {
//            ImmersionBar.with(this).hideBar(BarHide.FLAG_HIDE_BAR).init()
        } else {
            val navColor =
                if (appStore.isEyeCareMode) R.color.eye_protection_color else R.color.white
//            ImmersionBar.with(this).statusBarView(binding.view).statusBarDarkFont(true)
//                .navigationBarColor(navColor).hideBar(BarHide.FLAG_SHOW_BAR).init()
        }
    }

    private fun updateStatusAndNavigationLayout(b: Boolean) {
        if (b) {
            // 隐藏顶部和底部
            binding.statusLayout.visibility = View.GONE
            binding.navigationLayout.visibility = View.GONE
            binding.view.visibility = View.GONE
        } else {
            // 显示顶部和底部
            binding.statusLayout.visibility = View.VISIBLE
            binding.navigationLayout.visibility = View.VISIBLE
            binding.view.visibility = View.VISIBLE
        }
    }

    private fun toggleEyeCareMode(b: Boolean) {
        val navColor = if (b) R.color.eye_protection_color else R.color.white
        if (b) {
            binding.eyeCareOverlay.visibility = View.VISIBLE
            binding.eyeProtectIv.setImageResource(R.drawable.eye_protect_active)
        } else {
            binding.eyeCareOverlay.visibility = View.GONE
            binding.eyeProtectIv.setImageResource(R.drawable.eye_protect)
        }
//        ImmersionBar.with(this).statusBarView(binding.view).statusBarDarkFont(true)
//            .navigationBarColor(navColor).init()
    }

    private fun setupDoubleBackExit() {
        onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                if (showSearchTextView) {//如果当前是搜索，则退出搜索
                    showSearchTextView = false
                    updateSearchState(false)
                    clearHighlights()
                    binding.searchEdit.apply {
                        setText("")
                        clearComposingText()
                        setSelection(0)
                    }
                } else {
                    isEnabled = false // 解除拦截
                    onBackPressedDispatcher.onBackPressed() // 调用系统默认返回逻辑
                }
            }
        })
    }

    private fun updateSearchState(b: Boolean) {
        if (b) {
            binding.searchTextLayout.visibility = View.VISIBLE
            binding.navigationLayout.visibility = View.GONE
            binding.searchEdit.showKeyboard()
        } else {
            binding.searchTextLayout.visibility = View.GONE
            binding.navigationLayout.visibility = View.VISIBLE
            binding.searchEdit.hideKeyboard()
        }
    }

    private fun setupPDFSearchManager(password: String?) {
        searchManager = PDFSearchManager(binding.pdfview)
        highlighter = PDFHighlighter(binding.pdfview, searchManager)

        initSearchDocument(password)
    }

    private fun initSearchDocument(password: String?) {
        val file = File(pdfDocument.filePath)
        lifecycleScope.launch(Dispatchers.IO) {
            searchManager.getDocument(file, password, onLoaded = { doc ->
                lifecycleScope.launch(Dispatchers.IO) {
                    checkPageHasText(doc, binding.pdfview.currentPage)
                }
            }, onError = { e ->
                runOnUiThread {
                    binding.searchTextBtn.visibility = View.GONE
                    binding.searchTextBtn.isEnabled = false
                }
            })
        }
    }

    /**
     * 异步检查指定页是否有文字并更新按钮
     */
    private suspend fun checkPageHasText(doc: PDDocument, pageIndex: Int): Boolean {
        val hasText = searchManager.pageHasText(doc, pageIndex, minChars = 10) // 可调整阈值
        withContext(Dispatchers.Main) {
            if (hasText) {
                binding.searchTextBtn.visibility = View.VISIBLE
                binding.searchTextBtn.isEnabled = true
            } else {
                binding.searchTextBtn.visibility = View.GONE
                binding.searchTextBtn.isEnabled = false
            }
        }
        return hasText
    }

    private fun performSearch(searchText: String) {
        val file = File(pdfDocument.filePath)
        lifecycleScope.launch(Dispatchers.IO) {
            searchTextIng(file, searchText, binding.pdfview.currentPage)
        }
    }

    private fun searchTextIng(pdfFile: File, key: String, targetPage: Int? = null) {
        lifecycleScope.launch(Dispatchers.IO) {
            try {
                val results = searchManager.searchText(pdfFile, key, targetPage, currentPassword)

                withContext(Dispatchers.Main) {
                    if (!results.isEmpty()) {
                        binding.selectNextBtn.visibility = View.VISIBLE
                        binding.selectPreviousBtn.visibility = View.VISIBLE
                        results.firstOrNull()?.let { firstResult ->
                            onSearchResultClicked(firstResult)
                        }
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    private fun onSearchResultClicked(
        result: PDFSearchManager.TextSearchResult, isJumpTo: Boolean = false
    ) {
        if (isJumpTo) {
            // 跳转到对应页面 (PDFView 页面索引从0开始)
            binding.pdfview.jumpTo(result.pageNumber - 1)
        }

        // 设置高亮
        highlighter.setCurrentPageHighlights(result.pageNumber)
        // 标记已搜索高亮
        searchManager.currentSearchText = result.text
        searchManager.hasSearched = true
    }

    private fun clearHighlights() {
        searchManager.clearHighlights()
        highlighter.clearCurrentHighlights()
    }

    override fun onDestroy() {
        super.onDestroy()
        if (::searchManager.isInitialized) {
            searchManager.closeCachedDocument()
        }
    }

}