/*
 * 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 android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
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.IconProvider;
import com.android.storagemanager.utils.PreferenceListCache;

import java.io.File;
import java.util.Set;

/**
 * DownloadsDeletionPreferenceGroup defines a checkable preference group which contains
 * downloads file deletion preferences.
 */
public class DownloadsDeletionPreferenceGroup extends CollapsibleCheckboxPreferenceGroup
        implements DeletionType.FreeableChangedListener, Preference.OnPreferenceChangeListener {
    private DownloadsDeletionType mDeletionType;
    private DeletionType.FreeableChangedListener mListener;
    private IconProvider mIconProvider; // Purely for test.

    public DownloadsDeletionPreferenceGroup(Context context) {
        super(context);
        init();
    }

    public DownloadsDeletionPreferenceGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        setChecked(true);
        setOrderingAsAdded(false);
        setOnPreferenceChangeListener(this);
    }

    /**
     * Set up a deletion type to get info for the preference group.
     * @param type A {@link DownloadsDeletionType}.
     */
    public void registerDeletionService(DownloadsDeletionType type) {
        mDeletionType = type;
        mDeletionType.registerFreeableChangedListener(this);
    }

    /**
     * Registers a callback to be called when the amount of freeable space updates.
     * @param listener The callback listener.
     */
    public void registerFreeableChangedListener(DeletionType.FreeableChangedListener listener) {
        mListener = listener;
    }

    @Override
    public void onFreeableChanged(int numItems, long freeableBytes) {
        updatePreferenceText(numItems, freeableBytes, mDeletionType.getMostRecentLastModified());
        maybeUpdateListener(numItems, freeableBytes);
        switchSpinnerToCheckboxOrDisablePreference(freeableBytes, mDeletionType.getLoadingStatus());
        updateFiles();
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        boolean checked = (boolean) newValue;
        if (!checked) {
            // Temporarily stop listening to avoid propagating the checked change to children.
            setOnPreferenceChangeListener(null);
            setChecked(false);
            setOnPreferenceChangeListener(this);
        }

        // If we have no deletion type, we have no files to toggle.
        if (mDeletionType == null) {
            return true;
        }

        // If the group checkbox changed, we need to toggle every child preference.
        if (preference == this) {
            for (int i = 0; i < getPreferenceCount(); i++) {
                DownloadsFilePreference p = (DownloadsFilePreference) getPreference(i);
                p.setOnPreferenceChangeListener(null);
                mDeletionType.setFileChecked(p.getFile(), checked);
                p.setChecked(checked);
                p.setOnPreferenceChangeListener(this);
            }
            maybeUpdateListener(
                    mDeletionType.getFiles().size(),
                    mDeletionType.getFreeableBytes(DeletionHelperSettings.COUNT_CHECKED_ONLY));
            MetricsLogger.action(getContext(), MetricsEvent.ACTION_DELETION_SELECTION_DOWNLOADS,
                    checked);
            return true;
        }

        // If a single DownloadFilePreference changed, we need to toggle just itself.
        DownloadsFilePreference p = (DownloadsFilePreference) preference;
        mDeletionType.setFileChecked(p.getFile(), checked);
        maybeUpdateListener(
                mDeletionType.getFiles().size(),
                mDeletionType.getFreeableBytes(DeletionHelperSettings.COUNT_CHECKED_ONLY));
        return true;
    }

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

    @VisibleForTesting
    void injectIconProvider(IconProvider iconProvider) {
        mIconProvider = iconProvider;
    }

    private void updatePreferenceText(int itemCount, long bytes, long mostRecent) {
        Context context = getContext();
        setTitle(context.getString(R.string.deletion_helper_downloads_title));
        // If there are no files to clear, show the empty text instead.
        if (itemCount != 0) {
            setSummary(context.getString(R.string.deletion_helper_downloads_category_summary,
                    Formatter.formatFileSize(context, bytes)));
        } else {
            setSummary(context.getString(R.string.deletion_helper_downloads_summary_empty,
                    Formatter.formatFileSize(context, bytes)));
        }
    }

    private void maybeUpdateListener(int numItems, long bytesFreeable) {
        if (mListener != null) {
            mListener.onFreeableChanged(numItems, bytesFreeable);
        }
    }

    private void updateFiles() {
        PreferenceListCache cache = new PreferenceListCache(this);
        Set<File> files = mDeletionType.getFiles();
        Context context = getContext();
        Resources res = context.getResources();
        IconProvider iconProvider =
                mIconProvider == null ? new IconProvider(context) : mIconProvider;
        for (File file : files) {
            DownloadsFilePreference filePreference =
                    (DownloadsFilePreference) cache.getCachedPreference(file.getPath());
            if (filePreference == null) {
                filePreference = new DownloadsFilePreference(context, file, iconProvider);
                filePreference.setChecked(mDeletionType.isChecked(file));
                filePreference.setOnPreferenceChangeListener(this);
                Bitmap thumbnail = mDeletionType.getCachedThumbnail(file);
                if (thumbnail != null) {
                    filePreference.setIcon(new BitmapDrawable(res, thumbnail));
                }
            }
            addPreference(filePreference);
        }
        cache.removeCachedPrefs();
    }
}
