package com.kododake.aabrowser.ui

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.webkit.WebChromeClient
import android.widget.FrameLayout
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import com.google.android.material.button.MaterialButton
import com.kododake.aabrowser.R
import com.kododake.aabrowser.bookmarks.BookmarkManager
import com.kododake.aabrowser.data.BrowserPreferences
import com.kododake.aabrowser.databinding.ActivityMainBinding
import com.kododake.aabrowser.model.QuickActionButtonMode
import com.kododake.aabrowser.model.QuickActionButtonPosition
import com.kododake.aabrowser.startpage.StartPageManager
import com.kododake.aabrowser.tabs.TabManager

class BrowserUIManager(
    private val activity: AppCompatActivity,
    private val binding: ActivityMainBinding,
    private val tabManager: TabManager,
    private val bookmarkManager: BookmarkManager,
    private val startPageManager: StartPageManager,
    private val callbacks: UICallbacks
) {

    interface UICallbacks {
        fun onNavigateToAddress(raw: String, closeMenuAfterNavigate: Boolean)
        fun onShowQrCodeView()
        fun onShowCheckLatestView()
        fun onShowSettingsView()
        fun handleQuickActionButtonPressed()
        fun resolveThemeColor(attrRes: Int): Int
        fun showMenuButtonTemporarily()
    }

    private var isSyncingAddressFields: Boolean = false
    private var customView: View? = null
    private var customViewCallback: WebChromeClient.CustomViewCallback? = null

    fun configureAddressField(
        editText: com.google.android.material.textfield.TextInputEditText,
        clearButton: MaterialButton,
        goButton: MaterialButton,
        closeMenuAfterNavigate: Boolean
    ) {
        editText.setOnEditorActionListener { _, actionId, _ ->
            if (actionId == EditorInfo.IME_ACTION_GO) {
                callbacks.onNavigateToAddress(
                    editText.text?.toString().orEmpty(), 
                    closeMenuAfterNavigate
                )
                true
            } else {
                false
            }
        }

        editText.addTextChangedListener(object : android.text.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: android.text.Editable?) {
                syncAddressFieldsFrom(editText)
                updateAddressClearButtons()
            }
        })

        clearButton.setOnClickListener {
            editText.setText("")
            editText.requestFocus()
            showKeyboard(editText)
        }

        goButton.setOnClickListener {
            callbacks.onNavigateToAddress(
                editText.text?.toString().orEmpty(), 
                closeMenuAfterNavigate
            )
        }
    }

    fun syncAddressFieldsFrom(source: com.google.android.material.textfield.TextInputEditText) {
        if (isSyncingAddressFields) {
            return
        }
        
        val text = source.text?.toString().orEmpty()
        isSyncingAddressFields = true
        try {
            val addressEdit = binding.addressEdit
            val persistentAddressEdit = binding.persistentAddressEdit
            
            if (addressEdit !== source && addressEdit.text?.toString() != text) {
                addressEdit.setText(text)
                if (addressEdit.hasFocus()) {
                    addressEdit.setSelection(text.length)
                }
            }
            
            if (persistentAddressEdit !== source && persistentAddressEdit.text?.toString() != text) {
                persistentAddressEdit.setText(text)
                if (persistentAddressEdit.hasFocus()) {
                    persistentAddressEdit.setSelection(text.length)
                }
            }
        } finally {
            isSyncingAddressFields = false
        }
    }

    fun updateAddressClearButtons() {
        val hasAddressText = !binding.addressEdit.text.isNullOrEmpty()
        updateAddressClearButton(binding.buttonClearAddress, hasAddressText)
        
        val hasPersistentAddressText = !binding.persistentAddressEdit.text.isNullOrEmpty()
        updateAddressClearButton(binding.persistentButtonClearAddress, hasPersistentAddressText)
    }

    fun updateConnectionSecurityIcon(url: String?) {
        val icons = listOf(
            binding.addressSecureIcon, 
            binding.addressInsecureIcon, 
            binding.persistentAddressSecureIcon, 
            binding.persistentAddressInsecureIcon
        )
        
        if (url.isNullOrBlank()) {
            icons.forEach { it.visibility = View.GONE }
            return
        }
        
        val isSecure = try { 
            url.lowercase().startsWith("https://") 
        } catch (_: Exception) { 
            false 
        }
        
        binding.addressSecureIcon.isVisible = isSecure
        binding.addressInsecureIcon.isVisible = !isSecure
        binding.persistentAddressSecureIcon.isVisible = isSecure
        binding.persistentAddressInsecureIcon.isVisible = !isSecure
    }

    private fun updateAddressClearButton(button: View, shouldShow: Boolean) {
        if (shouldShow && button.visibility != View.VISIBLE) {
            button.visibility = View.VISIBLE
            button.alpha = 0f
            button.animate().alpha(1f).setDuration(150).start()
        } else if (!shouldShow && button.visibility == View.VISIBLE) {
            button.animate().alpha(0f).setDuration(100).withEndAction {
                button.visibility = View.GONE
            }.start()
        }
    }

    fun applyPersistentAddressBarPreference() {
        val shouldShow = BrowserPreferences.shouldAlwaysShowUrlBar(activity) && !isInFullscreen()
        binding.persistentAddressBarCard.isVisible = shouldShow

        val extraTopPadding = if (shouldShow) {
            persistentAddressBarHeightPx()
        } else {
            0
        }
        
        tabManager.browserTabs.forEach { tab ->
            tab.webView.setPadding(0, extraTopPadding, 0, 0)
        }

        val density = activity.resources.displayMetrics.density
        val startPagePadding = (24 * density).toInt()
        binding.startPageScroll.updatePadding(
            left = startPagePadding,
            top = startPagePadding + extraTopPadding,
            right = startPagePadding,
            bottom = startPagePadding
        )

        updateAddressClearButtons()
        applyQuickActionButtonPreferences()
    }

    private fun persistentAddressBarHeightPx(): Int {
        val density = activity.resources.displayMetrics.density
        return (76 * density).toInt()
    }

    fun applyQuickActionButtonPreferences() {
        val mode = BrowserPreferences.getQuickActionButtonMode(activity)
        val iconRes = if (mode == QuickActionButtonMode.ADDRESS_BAR) {
            R.drawable.search_24px
        } else {
            android.R.drawable.ic_menu_more
        }
        binding.menuFab.setImageResource(iconRes)
        
        val descriptionRes = if (mode == QuickActionButtonMode.ADDRESS_BAR) {
            R.string.menu_open_address_bar
        } else {
            R.string.menu_open_description
        }
        binding.menuFab.contentDescription = activity.getString(descriptionRes)

        val density = activity.resources.displayMetrics.density
        val margin = (16 * density).toInt()
        val position = BrowserPreferences.getQuickActionButtonPosition(activity)
        val layoutParams = binding.menuFab.layoutParams as CoordinatorLayout.LayoutParams
        
        layoutParams.gravity = when (position) {
            QuickActionButtonPosition.BOTTOM_LEFT -> android.view.Gravity.BOTTOM or android.view.Gravity.START
            QuickActionButtonPosition.BOTTOM_RIGHT -> android.view.Gravity.BOTTOM or android.view.Gravity.END
            QuickActionButtonPosition.TOP_LEFT -> android.view.Gravity.TOP or android.view.Gravity.START
            QuickActionButtonPosition.TOP_RIGHT -> android.view.Gravity.TOP or android.view.Gravity.END
        }

        val topOffset = if (position == QuickActionButtonPosition.TOP_LEFT || position == QuickActionButtonPosition.TOP_RIGHT) {
            val barHeight = if (binding.persistentAddressBarCard.isVisible) {
                persistentAddressBarHeightPx()
            } else {
                0
            }
            margin + barHeight
        } else {
            margin
        }
        
        layoutParams.setMargins(margin, topOffset, margin, margin)
        binding.menuFab.layoutParams = layoutParams

        val alwaysVisible = BrowserPreferences.isQuickActionButtonAlwaysVisible(activity)
        if (startPageManager.isShowingStartPage || alwaysVisible) {
            if (!isInFullscreen() && !binding.menuOverlay.isVisible) {
                binding.menuFab.show()
            }
        }
    }

    fun focusMenuAddressBar() {
        binding.addressEdit.requestFocus()
        val length = binding.addressEdit.text?.length ?: 0
        binding.addressEdit.setSelection(length)
        showKeyboard(binding.addressEdit)
    }

    fun showMenuOverlay(focusAddressBar: Boolean = false) {
        binding.menuOverlay.visibility = View.VISIBLE
        binding.menuCard.post {
            binding.menuCard.translationY = binding.menuCard.height.toFloat()
            binding.menuCard.animate()
                .translationY(0f)
                .setDuration(300)
                .setInterpolator(android.view.animation.DecelerateInterpolator())
                .start()
                
            binding.menuOverlayScrim.animate()
                .alpha(1f)
                .setDuration(300)
                .start()
                
            if (focusAddressBar) {
                focusMenuAddressBar()
            }
        }
        binding.menuFab.hide()
        bookmarkManager.refreshBookmarks()
        tabManager.refreshTabs()
        startPageManager.refreshStartPage()
    }

    fun hideMenuOverlay() {
        hideKeyboard(binding.addressEdit)
        binding.menuCard.animate()
            .translationY(binding.menuCard.height.toFloat())
            .setDuration(250)
            .setInterpolator(android.view.animation.AccelerateInterpolator())
            .withEndAction {
                binding.menuOverlay.visibility = View.GONE
                bookmarkManager.hideBookmarkManager()
                tabManager.hideTabManager()
                
                binding.checkLatestViewRoot.visibility = View.GONE
                binding.qrCodeViewRoot.visibility = View.GONE
                binding.settingsViewRoot.visibility = View.GONE
                
                callbacks.showMenuButtonTemporarily()
            }
            .start()
            
        binding.menuOverlayScrim.animate()
            .alpha(0f)
            .setDuration(200)
            .start()
    }

    fun openUriExternally(uri: Uri) {
        runCatching {
            val intent = Intent(Intent.ACTION_VIEW, uri)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            activity.startActivity(intent)
        }.onFailure {
            Toast.makeText(activity, R.string.error_open_external, Toast.LENGTH_SHORT).show()
        }
    }

    fun sanitizeJsExternalUrl(sourceWebView: android.webkit.WebView, rawUrl: String?): Uri? {
        val currentPage = sourceWebView.url
        if (currentPage == null) {
            return null
        }
        if (!currentPage.startsWith("file:///android_asset/error.html")) {
            return null
        }

        val candidate = rawUrl?.trim()
        if (candidate.isNullOrBlank()) {
            return null
        }
        
        val parsed = runCatching { Uri.parse(candidate) }.getOrNull()
        if (parsed == null) {
            return null
        }
        val scheme = parsed.scheme?.lowercase()
        if (scheme == null) {
            return null
        }
        if (scheme != "http" && scheme != "https") {
            return null
        }
        
        return parsed
    }

    fun showKeyboard(view: View) {
        val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        view.post { 
            imm.showSoftInput(view, 0) 
        }
    }

    fun hideKeyboard(view: View) {
        val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.hideSoftInputFromWindow(view.windowToken, 0)
    }

    fun isInFullscreen(): Boolean {
        return customView != null
    }

    fun enterFullscreen(view: View, callback: WebChromeClient.CustomViewCallback) {
        if (customView != null) {
            callback.onCustomViewHidden()
            return
        }
        
        (view.parent as? ViewGroup)?.removeView(view)
        customView = view
        customViewCallback = callback
        
        if (binding.menuOverlay.isVisible) {
            hideMenuOverlay()
        }
        
        binding.menuFab.hide()
        binding.persistentAddressBarCard.visibility = View.GONE
        tabManager.activeTab?.webView?.visibility = View.INVISIBLE
        
        binding.fullscreenContainer.apply {
            visibility = View.VISIBLE
            removeAllViews()
            addView(view, FrameLayout.LayoutParams(-1, -1))
            bringToFront()
        }
        
        activity.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        val controller = WindowInsetsControllerCompat(activity.window, binding.fullscreenContainer)
        controller.hide(WindowInsetsCompat.Type.systemBars())
    }

    fun setupManualDragLogic() {
        var startY = 0f
        var initialTranslationY = 0f
        val swipeThreshold = 250f

        binding.dragHandleArea.setOnTouchListener { _, event ->
            when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    startY = event.rawY
                    initialTranslationY = binding.menuCard.translationY
                    true
                }
                MotionEvent.ACTION_MOVE -> {
                    val deltaY = event.rawY - startY
                    if (deltaY > 0) {
                        binding.menuCard.translationY = initialTranslationY + deltaY
                        val progress = (deltaY / binding.menuCard.height.coerceAtLeast(1)).coerceIn(0f, 1f)
                        binding.menuOverlayScrim.alpha = 1f - progress
                    }
                    true
                }
                MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                    val totalDeltaY = event.rawY - startY
                    if (totalDeltaY > swipeThreshold) {
                        hideMenuOverlay()
                    } else {
                        binding.menuCard.animate()
                            .translationY(0f)
                            .setDuration(200)
                            .start()
                        binding.menuOverlayScrim.animate()
                            .alpha(1f)
                            .setDuration(200)
                            .start()
                    }
                    true
                }
                else -> false
            }
        }
    }

    fun exitFullscreen(fromWebChrome: Boolean = false) {
        if (customView == null) {
            return
        }
        
        binding.fullscreenContainer.apply { 
            removeAllViews()
            visibility = View.GONE 
        }
        
        val webViewVisibility = if (startPageManager.isShowingStartPage) {
            View.INVISIBLE
        } else {
            View.VISIBLE
        }
        tabManager.activeTab?.webView?.visibility = webViewVisibility
        
        activity.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        val controller = WindowInsetsControllerCompat(activity.window, binding.root)
        controller.show(WindowInsetsCompat.Type.systemBars())
        
        val callback = customViewCallback
        customView = null
        customViewCallback = null
        
        if (!fromWebChrome) {
            callback?.onCustomViewHidden()
        }
        
        applyPersistentAddressBarPreference()
        callbacks.showMenuButtonTemporarily()
    }
}
