/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.focus.input

import androidx.annotation.VisibleForTesting
import androidx.appcompat.widget.AppCompatEditText
import androidx.compose.material3.Text
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.launch
import mozilla.components.browser.domains.autocomplete.CustomDomainsProvider
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.browser.toolbar.display.DisplayToolbar.DisplayMargins
import mozilla.components.compose.cfr.CFRPopup
import mozilla.components.compose.cfr.CFRPopupProperties
import mozilla.components.concept.toolbar.AutocompleteResult
import mozilla.components.concept.toolbar.Toolbar
import mozilla.components.lib.state.ext.flowScoped
import mozilla.components.support.base.feature.LifecycleAwareFeature
import mozilla.components.support.ktx.android.util.dpToPx
import org.mozilla.focus.R
import org.mozilla.focus.ext.components
import org.mozilla.focus.ext.settings
import org.mozilla.focus.fragment.UrlInputFragment
import org.mozilla.focus.state.AppAction
import org.mozilla.focus.ui.theme.focusTypography
import androidx.cardview.R as cardViewR
import mozilla.components.browser.toolbar.R as toolbarR

/**
 * Integration for the URL input toolbar, managing editing and autocomplete.
 */
class InputToolbarIntegration(
    private val toolbar: BrowserToolbar,
    private val fragment: UrlInputFragment,
    shippedDomainsProvider: ShippedDomainsProvider,
    customDomainsProvider: CustomDomainsProvider,
    private val mainDispatcher: CoroutineDispatcher = Dispatchers.Main,
) : LifecycleAwareFeature {
    private val settings = toolbar.context.settings

    private var useShippedDomainProvider: Boolean = false
    private var useCustomDomainProvider: Boolean = false

    @VisibleForTesting
    internal var startBrowsingCfrScope: CoroutineScope? = null

    init {
        with(toolbar.display) {
            indicators = emptyList()
            hint = fragment.resources.getString(R.string.urlbar_hint)
            colors = toolbar.display.colors.copy(
                hint = ContextCompat.getColor(toolbar.context, R.color.urlBarHintText),
                text = ContextCompat.getColor(toolbar.context, R.color.primaryText),
            )
        }
        toolbar.edit.hint = fragment.resources.getString(R.string.urlbar_hint)
        toolbar.private = true
        toolbar.edit.colors = toolbar.edit.colors.copy(
            hint = ContextCompat.getColor(toolbar.context, R.color.urlBarHintText),
            text = ContextCompat.getColor(toolbar.context, R.color.primaryText),
            clear = ContextCompat.getColor(toolbar.context, R.color.primaryText),
            suggestionBackground = ContextCompat.getColor(toolbar.context, R.color.autocompleteBackgroundColor),
        )

        toolbar.setOnEditListener(
            object : Toolbar.OnEditListener {
                override fun onStartEditing() {
                    fragment.onStartEditing()
                }

                override fun onCancelEditing(): Boolean {
                    fragment.onCancelEditing()
                    return true
                }

                override fun onTextChanged(text: String) {
                    val lifecycleOwner = fragment.viewLifecycleOwnerLiveData.value ?: return
                    lifecycleOwner.lifecycleScope.launch {
                        fragment.onTextChange(text)
                    }
                }
            },
        )

        toolbar.setOnUrlCommitListener { url ->
            fragment.onCommit(url)
            false
        }

        toolbar.setAutocompleteListener { text, delegate ->
            var result: AutocompleteResult? = null
            if (useCustomDomainProvider) {
                result = customDomainsProvider.getAutocompleteSuggestion(text)
            }

            if (useShippedDomainProvider && result == null) {
                result = shippedDomainsProvider.getAutocompleteSuggestion(text)
            }

            if (result != null) {
                delegate.applyAutocompleteResult(
                    AutocompleteResult(
                        result.input,
                        result.text,
                        result.url,
                        result.source,
                        result.totalItems,
                    ),
                )
            } else {
                delegate.noAutocompleteResult(text)
            }
        }

        // Use the same background for display/edit modes.
        val urlBackground = ResourcesCompat.getDrawable(
            fragment.resources,
            R.drawable.toolbar_url_background,
            fragment.context?.theme,
        )

        toolbar.display.setUrlBackground(urlBackground)
        toolbar.display.setUrlBackgroundMargins(
            DisplayMargins(8.dpToPx(toolbar.resources.displayMetrics), 0),
        )

        toolbar.edit.setUrlBackground(urlBackground)
    }

    override fun start() {
        useCustomDomainProvider = settings.shouldAutocompleteFromCustomDomainList()
        useShippedDomainProvider = settings.shouldAutocompleteFromShippedDomainList()
        if (fragment.components?.appStore?.state?.showStartBrowsingTabsCfr == true) {
            observeStartBrowserCfrVisibility()
        }
    }

    @VisibleForTesting
    internal fun observeStartBrowserCfrVisibility() {
        startBrowsingCfrScope = fragment.components?.appStore?.flowScoped(dispatcher = mainDispatcher) { flow ->
            flow.mapNotNull { state -> state.showStartBrowsingTabsCfr }
                .distinctUntilChanged()
                .collect { showStartBrowsingCfr ->
                    if (showStartBrowsingCfr) {
                        CFRPopup(
                            anchor = toolbar.findViewById<AppCompatEditText>(
                                toolbarR.id.mozac_browser_toolbar_background,
                            ),
                            properties = CFRPopupProperties(
                                popupWidth = 256.dp,
                                popupAlignment = CFRPopup.PopupAlignment.BODY_TO_ANCHOR_START,
                                popupBodyColors = listOf(
                                    ContextCompat.getColor(
                                        fragment.requireContext(),
                                        R.color.cfr_pop_up_shape_end_color,
                                    ),
                                    ContextCompat.getColor(
                                        fragment.requireContext(),
                                        R.color.cfr_pop_up_shape_start_color,
                                    ),
                                ),
                                dismissButtonColor = ContextCompat.getColor(
                                    fragment.requireContext(),
                                    cardViewR.color.cardview_light_background,
                                ),
                                popupVerticalOffset = 0.dp,
                            ),
                            onDismiss = {
                                onDismissStartBrowsingCfr()
                            },
                            text = {
                                Text(
                                    style = focusTypography.cfrTextStyle,
                                    text = fragment.resources.getString(R.string.cfr_for_start_browsing),
                                    color = colorResource(R.color.cfr_text_color),
                                )
                            },
                        ).apply {
                            show()
                        }
                    }
                }
        }
    }

    private fun onDismissStartBrowsingCfr() {
        fragment.components?.appStore?.dispatch(AppAction.ShowStartBrowsingCfrChange(false))
        fragment.requireContext().settings.shouldShowStartBrowsingCfr = false
    }

    override fun stop() {
        startBrowsingCfrScope?.cancel()
    }
}
