/*
 *  Copyright (C) 2022 The Android Open Source Project
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package com.android.systemui.keyguard.data.quickaffordance

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.provider.Settings
import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
import android.provider.Settings.Global.ZEN_MODE_OFF
import android.provider.Settings.Secure.ZEN_DURATION_FOREVER
import android.provider.Settings.Secure.ZEN_DURATION_PROMPT
import android.service.notification.ZenModeConfig
import com.android.settingslib.notification.EnableZenModeDialog
import com.android.settingslib.notification.ZenModeDialogMetricsLogger
import com.android.systemui.res.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.ZenModeController
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart

@SysUISingleton
class DoNotDisturbQuickAffordanceConfig
constructor(
    private val context: Context,
    private val controller: ZenModeController,
    private val secureSettings: SecureSettings,
    private val userTracker: UserTracker,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
    private val testConditionId: Uri?,
    testDialog: EnableZenModeDialog?,
) : KeyguardQuickAffordanceConfig {

    @Inject
    constructor(
        context: Context,
        controller: ZenModeController,
        secureSettings: SecureSettings,
        userTracker: UserTracker,
        @Background backgroundDispatcher: CoroutineDispatcher,
    ) : this(context, controller, secureSettings, userTracker, backgroundDispatcher, null, null)

    private var dndMode: Int = 0
    private var isAvailable = false
    private var settingsValue: Int = 0

    private val conditionUri: Uri
        get() =
            testConditionId
                ?: ZenModeConfig.toTimeCondition(
                        context,
                        settingsValue,
                        userTracker.userId,
                        true, /* shortVersion */
                    )
                    .id

    private val dialog: EnableZenModeDialog by lazy {
        testDialog
            ?: EnableZenModeDialog(
                context,
                R.style.Theme_SystemUI_Dialog,
                true, /* cancelIsNeutral */
                ZenModeDialogMetricsLogger(context),
            )
    }

    override val key: String = BuiltInKeyguardQuickAffordanceKeys.DO_NOT_DISTURB

    override fun pickerName(): String = context.getString(R.string.quick_settings_dnd_label)

    override val pickerIconResourceId: Int = R.drawable.ic_do_not_disturb

    override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
        combine(
            conflatedCallbackFlow {
                val callback =
                    object : ZenModeController.Callback {
                        override fun onZenChanged(zen: Int) {
                            dndMode = zen
                            trySendWithFailureLogging(updateState(), TAG)
                        }

                        override fun onZenAvailableChanged(available: Boolean) {
                            isAvailable = available
                            trySendWithFailureLogging(updateState(), TAG)
                        }
                    }

                dndMode = controller.zen
                isAvailable = controller.isZenAvailable
                trySendWithFailureLogging(updateState(), TAG)

                controller.addCallback(callback)

                awaitClose { controller.removeCallback(callback) }
            },
            secureSettings
                .observerFlow(userTracker.userId, Settings.Secure.ZEN_DURATION)
                .onStart { emit(Unit) }
                .map { secureSettings.getInt(Settings.Secure.ZEN_DURATION, ZEN_MODE_OFF) }
                .flowOn(backgroundDispatcher)
                .distinctUntilChanged()
                .onEach { settingsValue = it }
        ) { callbackFlowValue, _ ->
            callbackFlowValue
        }

    override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
        return if (controller.isZenAvailable) {
            KeyguardQuickAffordanceConfig.PickerScreenState.Default(
                configureIntent = Intent(Settings.ACTION_ZEN_MODE_SETTINGS)
            )
        } else {
            KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
        }
    }

    override fun onTriggered(
        expandable: Expandable?
    ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
        return when {
            !isAvailable -> KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
            dndMode != ZEN_MODE_OFF -> {
                controller.setZen(ZEN_MODE_OFF, null, TAG)
                KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
            }
            settingsValue == ZEN_DURATION_PROMPT ->
                KeyguardQuickAffordanceConfig.OnTriggeredResult.ShowDialog(
                    dialog.createDialog(),
                    expandable
                )
            settingsValue == ZEN_DURATION_FOREVER -> {
                controller.setZen(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG)
                KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
            }
            else -> {
                controller.setZen(ZEN_MODE_IMPORTANT_INTERRUPTIONS, conditionUri, TAG)
                KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
            }
        }
    }

    private fun updateState(): KeyguardQuickAffordanceConfig.LockScreenState {
        return if (!isAvailable) {
            KeyguardQuickAffordanceConfig.LockScreenState.Hidden
        } else if (dndMode == ZEN_MODE_OFF) {
            KeyguardQuickAffordanceConfig.LockScreenState.Visible(
                Icon.Resource(
                    R.drawable.qs_dnd_icon_off,
                    ContentDescription.Resource(R.string.dnd_is_off),
                ),
                ActivationState.Inactive,
            )
        } else {
            KeyguardQuickAffordanceConfig.LockScreenState.Visible(
                Icon.Resource(
                    R.drawable.qs_dnd_icon_on,
                    ContentDescription.Resource(R.string.dnd_is_on),
                ),
                ActivationState.Active,
            )
        }
    }

    companion object {
        const val TAG = "DoNotDisturbQuickAffordanceConfig"
    }
}
