/* 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.fenix.components.toolbar

import android.content.Context
import android.content.res.Configuration
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import kotlinx.coroutines.ExperimentalCoroutinesApi
import mozilla.components.browser.domains.autocomplete.DomainAutocompleteProvider
import mozilla.components.browser.state.selector.normalTabs
import mozilla.components.browser.state.selector.privateTabs
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.browser.toolbar.display.DisplayToolbar
import mozilla.components.concept.engine.Engine
import mozilla.components.concept.storage.HistoryStorage
import mozilla.components.feature.tabs.toolbar.TabCounterToolbarButton
import mozilla.components.feature.toolbar.ToolbarAutocompleteFeature
import mozilla.components.feature.toolbar.ToolbarFeature
import mozilla.components.feature.toolbar.ToolbarPresenter
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
import mozilla.components.support.base.feature.LifecycleAwareFeature
import mozilla.components.support.ktx.android.view.hideKeyboard
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.theme.ThemeManager

@ExperimentalCoroutinesApi
abstract class ToolbarIntegration(
    context: Context,
    toolbar: BrowserToolbar,
    toolbarMenu: ToolbarMenu,
    sessionId: String?,
    isPrivate: Boolean,
    renderStyle: ToolbarFeature.RenderStyle
) : LifecycleAwareFeature {

    val store = context.components.core.store
    private val toolbarPresenter: ToolbarPresenter = ToolbarPresenter(
        toolbar,
        store,
        sessionId,
        ToolbarFeature.UrlRenderConfiguration(
            PublicSuffixList(context),
            ThemeManager.resolveAttribute(R.attr.primaryText, context),
            renderStyle = renderStyle
        )
    )

    private val menuPresenter =
        MenuPresenter(toolbar, context.components.core.store, sessionId)

    init {
        toolbar.display.menuBuilder = toolbarMenu.menuBuilder
        toolbar.private = isPrivate
    }

    override fun start() {
        menuPresenter.start()
        toolbarPresenter.start()
    }

    override fun stop() {
        menuPresenter.stop()
        toolbarPresenter.stop()
    }

    fun invalidateMenu() {
        menuPresenter.invalidateActions()
    }
}

@ExperimentalCoroutinesApi
class DefaultToolbarIntegration(
    context: Context,
    toolbar: BrowserToolbar,
    toolbarMenu: ToolbarMenu,
    domainAutocompleteProvider: DomainAutocompleteProvider,
    historyStorage: HistoryStorage,
    lifecycleOwner: LifecycleOwner,
    sessionId: String? = null,
    isPrivate: Boolean,
    interactor: BrowserToolbarViewInteractor,
    engine: Engine
) : ToolbarIntegration(
    context = context,
    toolbar = toolbar,
    toolbarMenu = toolbarMenu,
    sessionId = sessionId,
    isPrivate = isPrivate,
    renderStyle = ToolbarFeature.RenderStyle.UncoloredUrl
) {

    init {
        toolbar.display.menuBuilder = toolbarMenu.menuBuilder
        toolbar.private = isPrivate

        val drawable =
            if (isPrivate) AppCompatResources.getDrawable(
                context,
                R.drawable.shield_dark
            ) else when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
                Configuration.UI_MODE_NIGHT_UNDEFINED, // We assume light here per Android doc's recommendation
                Configuration.UI_MODE_NIGHT_NO -> {
                    AppCompatResources.getDrawable(context, R.drawable.shield_light)
                }
                Configuration.UI_MODE_NIGHT_YES -> {
                    AppCompatResources.getDrawable(context, R.drawable.shield_dark)
                }
                else -> AppCompatResources.getDrawable(context, R.drawable.shield_light)
            }

        toolbar.display.indicators =
            if (context.settings().shouldUseTrackingProtection) {
                listOf(
                    DisplayToolbar.Indicators.TRACKING_PROTECTION,
                    DisplayToolbar.Indicators.SECURITY,
                    DisplayToolbar.Indicators.EMPTY
                )
            } else {
                listOf(
                    DisplayToolbar.Indicators.SECURITY,
                    DisplayToolbar.Indicators.EMPTY
                )
            }

        if (FeatureFlags.permissionIndicatorsToolbar) {
            toolbar.display.indicators += DisplayToolbar.Indicators.PERMISSION_HIGHLIGHTS
        }

        toolbar.display.displayIndicatorSeparator =
            context.settings().shouldUseTrackingProtection

        toolbar.display.icons = toolbar.display.icons.copy(
            emptyIcon = null,
            trackingProtectionTrackersBlocked = drawable!!,
            trackingProtectionNothingBlocked = AppCompatResources.getDrawable(
                context,
                R.drawable.ic_tracking_protection_enabled
            )!!,
            trackingProtectionException = AppCompatResources.getDrawable(
                context,
                R.drawable.ic_tracking_protection_disabled
            )!!
        )

        val tabCounterMenu = FenixTabCounterMenu(
            context = context,
            onItemTapped = {
                interactor.onTabCounterMenuItemTapped(it)
            },
            iconColor =
                if (isPrivate) {
                    ContextCompat.getColor(context, R.color.primary_text_private_theme)
                } else {
                    null
                }
        ).also {
            it.updateMenu(context.settings().toolbarPosition)
        }

        val tabsAction = TabCounterToolbarButton(
            lifecycleOwner = lifecycleOwner,
            showTabs = {
                toolbar.hideKeyboard()
                interactor.onTabCounterClicked()
            },
            store = store,
            menu = tabCounterMenu,
            privateColor = ContextCompat.getColor(context, R.color.primary_text_private_theme)
        )

        val tabCount = if (isPrivate) {
            store.state.privateTabs.size
        } else {
            store.state.normalTabs.size
        }

        tabsAction.updateCount(tabCount)

        toolbar.addBrowserAction(tabsAction)

        val engineForSpeculativeConnects = if (!isPrivate) engine else null
        ToolbarAutocompleteFeature(
            toolbar,
            engineForSpeculativeConnects
        ).apply {
            addDomainProvider(domainAutocompleteProvider)
            if (context.settings().shouldShowHistorySuggestions) {
                addHistoryStorageProvider(historyStorage)
            }
        }
    }
}
