/* 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.settings.quicksettings

import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import mozilla.components.feature.sitepermissions.SitePermissions
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter
import org.mozilla.fenix.settings.PhoneFeature
import kotlin.coroutines.CoroutineContext

private const val KEY_URL = "KEY_URL"
private const val KEY_IS_SECURED = "KEY_IS_SECURED"
private const val KEY_SITE_PERMISSIONS = "KEY_SITE_PERMISSIONS"
private const val REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS = 4

@SuppressWarnings("TooManyFunctions")
class QuickSettingsSheetDialogFragment : BottomSheetDialogFragment(), CoroutineScope {
    private val safeArguments get() = requireNotNull(arguments)
    private val url: String by lazy { safeArguments.getString(KEY_URL) }
    private val isSecured: Boolean by lazy { safeArguments.getBoolean(KEY_IS_SECURED) }
    private lateinit var quickSettingsComponent: QuickSettingsComponent
    private lateinit var job: Job

    var sitePermissions: SitePermissions?
        get() = safeArguments.getParcelable(KEY_SITE_PERMISSIONS)
        set(value) {
            safeArguments.putParcelable(KEY_SITE_PERMISSIONS, value)
        }

    override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        job = Job()
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_quick_settings_dialog_sheet, container, false)
    }

    override fun onViewCreated(rootView: View, savedInstanceState: Bundle?) {
        super.onViewCreated(rootView, savedInstanceState)
        quickSettingsComponent = QuickSettingsComponent(
            rootView as ConstraintLayout, ActionBusFactory.get(this),
            QuickSettingsState(
                QuickSettingsState.Mode.Normal(url, isSecured, sitePermissions)
            )
        )
    }

    companion object {
        const val FRAGMENT_TAG = "QUICK_SETTINGS_FRAGMENT_TAG"

        fun newInstance(
            url: String,
            isSecured: Boolean,
            sitePermissions: SitePermissions?
        ): QuickSettingsSheetDialogFragment {

            val fragment = QuickSettingsSheetDialogFragment()
            val arguments = fragment.arguments ?: Bundle()

            with(arguments) {
                putString(KEY_URL, url)
                putBoolean(KEY_IS_SECURED, isSecured)
                putParcelable(KEY_SITE_PERMISSIONS, sitePermissions)
            }
            fragment.arguments = arguments
            return fragment
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        if (arePermissionsGranted(requestCode, grantResults)) {
            val feature = requireNotNull(PhoneFeature.findFeatureBy(permissions))
            getManagedEmitter<QuickSettingsChange>()
                .onNext(QuickSettingsChange.PermissionGranted(feature, sitePermissions))
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        job.cancel()
    }

    private fun arePermissionsGranted(requestCode: Int, grantResults: IntArray) =
        requestCode == REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS && grantResults.all { it == PERMISSION_GRANTED }

    override fun onResume() {
        super.onResume()
        getAutoDisposeObservable<QuickSettingsAction>()
            .subscribe {
                when (it) {
                    is QuickSettingsAction.SelectBlockedByAndroid -> {
                        requestPermissions(it.permissions, REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS)
                    }
                    is QuickSettingsAction.TogglePermission -> {

                        launch {
                            sitePermissions = quickSettingsComponent.toggleSitePermission(
                                context = requireContext(),
                                featurePhone = it.featurePhone,
                                url = url,
                                sitePermissions = sitePermissions
                            )

                            launch(Dispatchers.Main) {
                                getManagedEmitter<QuickSettingsChange>()
                                    .onNext(QuickSettingsChange.Stored(it.featurePhone, sitePermissions))

                                requireContext().components.useCases.sessionUseCases.reload.invoke()
                            }
                        }
                    }
                }
            }

        if (isVisible) {
            getManagedEmitter<QuickSettingsChange>()
                .onNext(QuickSettingsChange.PromptRestarted(sitePermissions))
        }
    }
}
