/*
 * Copyright (C) 2020 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.settings.applications.specialaccess.notificationaccess;

import android.app.NotificationManager;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;

import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.RestrictedSwitchPreference;

public class ApprovalPreferenceController extends BasePreferenceController {

    private static final String TAG = "ApprovalPrefController";

    private PackageInfo mPkgInfo;
    private ComponentName mCn;
    private PreferenceFragmentCompat mParent;
    private NotificationManager mNm;
    private PackageManager mPm;
    // The appOp representing this preference
    private String mSettingIdentifier;

    public ApprovalPreferenceController(Context context, String key) {
        super(context, key);
    }

    public ApprovalPreferenceController setPkgInfo(PackageInfo pkgInfo) {
        mPkgInfo = pkgInfo;
        return this;
    }

    public ApprovalPreferenceController setCn(ComponentName cn) {
        mCn = cn;
        return this;
    }

    public ApprovalPreferenceController setParent(PreferenceFragmentCompat parent) {
        mParent = parent;
        return this;
    }

    public ApprovalPreferenceController setNm(NotificationManager nm) {
        mNm = nm;
        return this;
    }

    public ApprovalPreferenceController setPm(PackageManager pm) {
        mPm = pm;
        return this;
    }

    /**
     * Set the associated appOp for the Setting
     */
    @NonNull
    public ApprovalPreferenceController setSettingIdentifier(@NonNull String settingIdentifier) {
        mSettingIdentifier = settingIdentifier;
        return this;
    }

    @Override
    public int getAvailabilityStatus() {
        return AVAILABLE;
    }

    @Override
    public void updateState(Preference pref) {
        final RestrictedSwitchPreference preference =
                (RestrictedSwitchPreference) pref;
        final CharSequence label = mPkgInfo.applicationInfo.loadLabel(mPm);
        final boolean isAllowedCn = mCn.flattenToShortString().length()
                <= NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH;
        final boolean isEnabled = isServiceEnabled(mCn);
        preference.setChecked(isEnabled);
        preference.setOnPreferenceChangeListener((p, newValue) -> {
            final boolean access = (Boolean) newValue;
            if (!access) {
                if (!isServiceEnabled(mCn)) {
                    return true; // already disabled
                }
                // show a friendly dialog
                new FriendlyWarningDialogFragment()
                        .setServiceInfo(mCn, label, mParent)
                        .show(mParent.getFragmentManager(), "friendlydialog");
                return false;
            } else {
                if (isServiceEnabled(mCn)) {
                    return true; // already enabled
                }
                // show a scary dialog
                new ScaryWarningDialogFragment()
                        .setServiceInfo(mCn, label, mParent)
                        .show(mParent.getFragmentManager(), "dialog");
                return false;
            }
        });

        if (android.permission.flags.Flags.enhancedConfirmationModeApisEnabled()
                && android.security.Flags.extendEcmToAllSettings()) {
            if (!isAllowedCn && !isEnabled) {
                preference.setEnabled(false);
            } else if (isEnabled) {
                preference.setEnabled(true);
            } else {
                preference.checkEcmRestrictionAndSetDisabled(mSettingIdentifier,
                        mCn.getPackageName());
            }
        } else {
            preference.updateState(
                    mCn.getPackageName(), mPkgInfo.applicationInfo.uid, isAllowedCn, isEnabled);
        }
    }

    public void disable(final ComponentName cn) {
        logSpecialPermissionChange(true, cn.getPackageName());
        mNm.setNotificationListenerAccessGranted(cn, false);
        if (!mNm.isNotificationPolicyAccessGrantedForPackage(
                cn.getPackageName())) {
            if (android.app.Flags.modesApi()) {
                mNm.removeAutomaticZenRules(cn.getPackageName(), /* fromUser= */ true);
            } else {
                mNm.removeAutomaticZenRules(cn.getPackageName());
            }
        }
    }

    protected void enable(ComponentName cn) {
        logSpecialPermissionChange(true, cn.getPackageName());
        mNm.setNotificationListenerAccessGranted(cn, true);
    }

    protected boolean isServiceEnabled(ComponentName cn) {
        return mNm.isNotificationListenerAccessGranted(cn);
    }

    @VisibleForTesting
    void logSpecialPermissionChange(boolean enable, String packageName) {
        final int logCategory = enable ? SettingsEnums.APP_SPECIAL_PERMISSION_NOTIVIEW_ALLOW
                : SettingsEnums.APP_SPECIAL_PERMISSION_NOTIVIEW_DENY;
        FeatureFactory.getFeatureFactory().getMetricsFeatureProvider().action(mContext,
                logCategory, packageName);
    }
}