/*
 * Copyright (C) 2016 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.storagemanager.deletionhelper;

import android.content.Context;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import android.text.format.Formatter;
import android.util.AttributeSet;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.storagemanager.R;
import com.android.storagemanager.utils.PreferenceListCache;
import java.util.List;

/**
 * AppDeletionPreferenceGroup is a collapsible checkbox preference group which contains many
 * apps to be cleared in the Deletion Helper.
 */
public class AppDeletionPreferenceGroup extends CollapsibleCheckboxPreferenceGroup
        implements AppDeletionType.AppListener, Preference.OnPreferenceChangeListener {
    private static final int ORDER_OFFSET = 100;
    private AppDeletionType mBackend;

    @VisibleForTesting PreferenceScreen mScreen;

    public AppDeletionPreferenceGroup(Context context) {
        this(context, null);
    }

    public AppDeletionPreferenceGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        setOnPreferenceChangeListener(this);
        updateText();
    }

    @Override
    public void onAppRebuild(List<AppsAsyncLoader.PackageInfo> apps) {
        int appCount = apps.size();
        int currentUserId = getContext().getUserId();
        PreferenceListCache cache = new PreferenceListCache(this);
        for (int i = 0; i < appCount; i++) {
            AppsAsyncLoader.PackageInfo app = apps.get(i);

            if (app.userId != currentUserId) {
                continue;
            }

            final String packageName = app.packageName;
            AppDeletionPreference preference =
                    (AppDeletionPreference) cache.getCachedPreference(packageName);
            if (preference == null) {
                preference = new AppDeletionPreference(getContext(), app);
                preference.setKey(packageName);
                preference.setOnPreferenceChangeListener(this);
            }
            addThresholdDependentPreference(preference, isNoThreshold());
            preference.setChecked(mBackend.isChecked(packageName));
            preference.setOrder(i + ORDER_OFFSET);
            preference.updateSummary();
        }
        cache.removeCachedPrefs();
        updateText();
    }

    private void addThresholdDependentPreference(
            AppDeletionPreference preference, boolean isThresholded) {
        if (isNoThreshold()) {
            addPreferenceToScreen(preference);
        } else {
            addPreference(preference);
        }
    }

    private boolean isNoThreshold() {
        return mBackend.getDeletionThreshold() == 0;
    }

    @VisibleForTesting
    void addPreferenceToScreen(AppDeletionPreference preference) {
        if (mScreen == null) {
            mScreen = getPreferenceManager().getPreferenceScreen();
        }
        mScreen.addPreference(preference);
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        boolean isChecked = (boolean) newValue;

        // If we have no AppDeletionType, we have no apps to toggle.
        if (mBackend == null) {
            return true;
        }

        if (preference == this) {
            for (int i = 0; i < getPreferenceCount(); i++) {
                AppDeletionPreference p = (AppDeletionPreference) getPreference(i);
                p.setOnPreferenceChangeListener(null);
                p.setChecked(isChecked);
                mBackend.setChecked(p.getPackageName(), isChecked);
                p.setOnPreferenceChangeListener(this);
            }
            updateText();
            MetricsLogger.action(getContext(), MetricsEvent.ACTION_DELETION_SELECTION_ALL_APPS,
                    isChecked);
            return true;
        }

        // If a single preference changed, we need to toggle just itself.
        AppDeletionPreference p = (AppDeletionPreference) preference;
        mBackend.setChecked(p.getPackageName(), isChecked);
        logAppToggle(isChecked, p.getPackageName());
        updateText();
        return true;
    }

    @Override
    public void onClick() {
        super.onClick();
        MetricsLogger.action(
                getContext(), MetricsEvent.ACTION_DELETION_APPS_COLLAPSED, isCollapsed());
    }

    /**
     * Initializes the PreferenceGroup with a source of apps to list.
     *
     * @param type The AppDeletionType which provides the app list.
     */
    public void setDeletionType(AppDeletionType type) {
        mBackend = type;
    }

    private void updateText() {
        long freeableBytes = 0;
        long deletionThreshold = AppsAsyncLoader.UNUSED_DAYS_DELETION_THRESHOLD;
        if (mBackend != null) {
            freeableBytes =
                    mBackend.getTotalAppsFreeableSpace(DeletionHelperSettings.COUNT_UNCHECKED);
            deletionThreshold = mBackend.getDeletionThreshold();
            switchSpinnerToCheckboxOrDisablePreference(freeableBytes, mBackend.getLoadingStatus());
        }
        Context app = getContext();
        setTitle(app.getString(R.string.deletion_helper_apps_group_title));
        setSummary(
                app.getString(
                        R.string.deletion_helper_apps_group_summary,
                        Formatter.formatFileSize(app, freeableBytes),
                        deletionThreshold));
    }

    private void logAppToggle(boolean checked, String packageName) {
        if (checked) {
            MetricsLogger.action(
                    getContext(), MetricsEvent.ACTION_DELETION_SELECTION_APP_ON, packageName);
        } else {
            MetricsLogger.action(getContext(), MetricsEvent.ACTION_DELETION_SELECTION_APP_OFF,
                    packageName);
        }
    }
}
