/*
 * Copyright (C) 2023 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.statusbar.notification.interruption

import android.app.NotificationManager.IMPORTANCE_HIGH
import android.os.PowerManager
import com.android.internal.logging.UiEventLogger.UiEventEnum
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState.KEYGUARD
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_DEVICE_DREAMING
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_DEVICE_NOT_INTERACTIVE
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_DEVICE_NOT_PROVISIONED
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_KEYGUARD_OCCLUDED
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_KEYGUARD_SHOWING
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.FSI_LOCKED_SHADE
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_EXPECTED_TO_HUN
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_NOT_IMPORTANT_ENOUGH
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_NO_FULL_SCREEN_INTENT
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_NO_HUN_OR_KEYGUARD
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_PACKAGE_SUSPENDED
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_SHOW_STICKY_HUN
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_SUPPRESSED_BY_DND
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_SUPPRESSED_ONLY_BY_DND
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_SUPPRESSIVE_BUBBLE_METADATA
import com.android.systemui.statusbar.notification.interruption.FullScreenIntentDecisionProvider.DecisionImpl.NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionSuppressor.EventLogData
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.statusbar.policy.KeyguardStateController

class FullScreenIntentDecisionProvider(
    private val deviceProvisionedController: DeviceProvisionedController,
    private val keyguardStateController: KeyguardStateController,
    private val powerManager: PowerManager,
    private val statusBarStateController: StatusBarStateController
) {
    interface Decision {
        val shouldFsi: Boolean
        val wouldFsiWithoutDnd: Boolean
        val logReason: String
        val shouldLog: Boolean
        val isWarning: Boolean
        val uiEventId: UiEventEnum?
        val eventLogData: EventLogData?
    }

    private enum class DecisionImpl(
        override val shouldFsi: Boolean,
        override val logReason: String,
        override val wouldFsiWithoutDnd: Boolean = shouldFsi,
        val supersedesDnd: Boolean = false,
        override val shouldLog: Boolean = true,
        override val isWarning: Boolean = false,
        override val uiEventId: UiEventEnum? = null,
        override val eventLogData: EventLogData? = null
    ) : Decision {
        NO_FSI_NO_FULL_SCREEN_INTENT(
            false,
            "no full-screen intent",
            supersedesDnd = true,
            shouldLog = false
        ),
        NO_FSI_SHOW_STICKY_HUN(false, "full-screen intents are disabled", supersedesDnd = true),
        NO_FSI_NOT_IMPORTANT_ENOUGH(false, "not important enough"),
        NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR(
            false,
            "suppressive group alert behavior",
            isWarning = true,
            uiEventId = FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR,
            eventLogData = EventLogData("231322873", "groupAlertBehavior")
        ),
        NO_FSI_SUPPRESSIVE_BUBBLE_METADATA(
            false,
            "suppressive bubble metadata",
            isWarning = true,
            uiEventId = FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA,
            eventLogData = EventLogData("274759612", "bubbleMetadata")
        ),
        NO_FSI_PACKAGE_SUSPENDED(false, "package suspended"),
        FSI_DEVICE_NOT_INTERACTIVE(true, "device is not interactive"),
        FSI_DEVICE_DREAMING(true, "device is dreaming"),
        FSI_KEYGUARD_SHOWING(true, "keyguard is showing"),
        NO_FSI_EXPECTED_TO_HUN(false, "expected to heads-up instead"),
        FSI_KEYGUARD_OCCLUDED(true, "keyguard is occluded"),
        FSI_LOCKED_SHADE(true, "locked shade"),
        FSI_DEVICE_NOT_PROVISIONED(true, "device not provisioned"),
        NO_FSI_NO_HUN_OR_KEYGUARD(
            false,
            "no HUN or keyguard",
            isWarning = true,
            uiEventId = FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD,
            eventLogData = EventLogData("231322873", "no hun or keyguard")
        ),
        NO_FSI_SUPPRESSED_BY_DND(false, "suppressed by DND", wouldFsiWithoutDnd = false),
        NO_FSI_SUPPRESSED_ONLY_BY_DND(false, "suppressed only by DND", wouldFsiWithoutDnd = true)
    }

    fun makeFullScreenIntentDecision(entry: NotificationEntry, couldHeadsUp: Boolean): Decision {
        val reasonWithoutDnd = makeDecisionWithoutDnd(entry, couldHeadsUp)

        val suppressedWithoutDnd = !reasonWithoutDnd.shouldFsi
        val suppressedByDnd = entry.shouldSuppressFullScreenIntent()

        val reasonWithDnd =
            when {
                reasonWithoutDnd.supersedesDnd -> reasonWithoutDnd
                suppressedByDnd && !suppressedWithoutDnd -> NO_FSI_SUPPRESSED_ONLY_BY_DND
                suppressedByDnd -> NO_FSI_SUPPRESSED_BY_DND
                else -> reasonWithoutDnd
            }

        return reasonWithDnd
    }

    private fun makeDecisionWithoutDnd(
        entry: NotificationEntry,
        couldHeadsUp: Boolean
    ): DecisionImpl {
        val sbn = entry.sbn
        val notification = sbn.notification!!

        if (notification.fullScreenIntent == null) {
            return if (entry.isStickyAndNotDemoted) {
                NO_FSI_SHOW_STICKY_HUN
            } else {
                NO_FSI_NO_FULL_SCREEN_INTENT
            }
        }

        if (entry.importance < IMPORTANCE_HIGH) {
            return NO_FSI_NOT_IMPORTANT_ENOUGH
        }

        if (sbn.isGroup && notification.suppressAlertingDueToGrouping()) {
            return NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR
        }

        val bubbleMetadata = notification.bubbleMetadata
        if (bubbleMetadata != null && bubbleMetadata.isNotificationSuppressed) {
            return NO_FSI_SUPPRESSIVE_BUBBLE_METADATA
        }

        if (entry.ranking.isSuspended) {
            return NO_FSI_PACKAGE_SUSPENDED
        }

        if (!powerManager.isInteractive) {
            return FSI_DEVICE_NOT_INTERACTIVE
        }

        if (statusBarStateController.isDreaming) {
            return FSI_DEVICE_DREAMING
        }

        if (statusBarStateController.state == KEYGUARD) {
            return FSI_KEYGUARD_SHOWING
        }

        if (couldHeadsUp) {
            return NO_FSI_EXPECTED_TO_HUN
        }

        if (keyguardStateController.isShowing) {
            return if (keyguardStateController.isOccluded) {
                FSI_KEYGUARD_OCCLUDED
            } else {
                FSI_LOCKED_SHADE
            }
        }

        if (!deviceProvisionedController.isDeviceProvisioned) {
            return FSI_DEVICE_NOT_PROVISIONED
        }

        return NO_FSI_NO_HUN_OR_KEYGUARD
    }
}
