/*
 * 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.permissioncontroller.safetycenter.ui;

import static android.content.Intent.ACTION_SAFETY_CENTER;
import static android.content.Intent.FLAG_ACTIVITY_FORWARD_RESULT;
import static android.os.Build.VERSION_CODES.TIRAMISU;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCES_GROUP_ID;

import static com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION;
import static com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__NOTIFICATION_CLICKED;
import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.EXTRA_SETTINGS_FRAGMENT_ARGS_KEY;
import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PERSONAL_PROFILE_SUFFIX;
import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PRIVACY_SOURCES_GROUP_ID;
import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PRIVATE_PROFILE_SUFFIX;
import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.WORK_PROFILE_SUFFIX;

import android.app.ActionBar;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.provider.Settings;
import android.safetycenter.SafetyCenterManager;
import android.safetycenter.config.SafetyCenterConfig;
import android.safetycenter.config.SafetySource;
import android.safetycenter.config.SafetySourcesGroup;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceFragmentCompat;

import com.android.permissioncontroller.Constants;
import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.utils.Utils;
import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModel.Pref;
import com.android.settingslib.activityembedding.ActivityEmbeddingUtils;
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;

import java.util.List;
import java.util.Objects;

/** Entry-point activity for SafetyCenter. */
@RequiresApi(TIRAMISU)
public final class SafetyCenterActivity extends CollapsingToolbarBaseActivity {

    private static final String TAG = SafetyCenterActivity.class.getSimpleName();
    private static final String PRIVACY_CONTROLS_ACTION = "android.settings.PRIVACY_CONTROLS";
    private static final String MENU_KEY_SAFETY_CENTER = "top_level_safety_center";
    private static final String EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI =
            "android.provider.extra.SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI";
    private static final String EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY =
            "android.provider.extra.SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY";
    private static final String EXTRA_PREVENT_TRAMPOLINE_TO_SETTINGS =
            "com.android.permissioncontroller.safetycenter.extra.PREVENT_TRAMPOLINE_TO_SETTINGS";

    private SafetyCenterManager mSafetyCenterManager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mSafetyCenterManager = getSystemService(SafetyCenterManager.class);

        if (maybeRedirectIfDisabled()) {
            return;
        }

        if (maybeRedirectIntoTwoPaneSettings()) {
            return;
        }

        Fragment frag;
        final boolean maybeOpenSubpage =
                SafetyCenterUiFlags.getShowSubpages()
                        && getIntent().getAction().equals(ACTION_SAFETY_CENTER);
        if (maybeOpenSubpage && getIntent().hasExtra(EXTRA_SAFETY_SOURCES_GROUP_ID)) {
            String groupId = getIntent().getStringExtra(EXTRA_SAFETY_SOURCES_GROUP_ID);
            frag = openRelevantSubpage(groupId);
        } else if (maybeOpenSubpage && getIntent().hasExtra(EXTRA_SETTINGS_FRAGMENT_ARGS_KEY)) {
            String preferenceKey = getIntent().getStringExtra(EXTRA_SETTINGS_FRAGMENT_ARGS_KEY);
            String groupId = getParentGroupId(preferenceKey);
            frag = openRelevantSubpage(groupId);
        } else if (getIntent().getAction().equals(PRIVACY_CONTROLS_ACTION)) {
            setTitle(R.string.privacy_controls_title);
            frag = PrivacyControlsFragment.newInstance();
        } else {
            frag = openHomepage();
        }

        if (savedInstanceState == null) {
            getSupportFragmentManager()
                    .beginTransaction()
                    .add(com.android.settingslib.collapsingtoolbar.R.id.content_frame, frag)
                    .commitNow();
        }

        configureHomeButton();

        frag.getLifecycle()
                .addObserver(
                        new LifecycleEventObserver() {
                            @Override
                            public void onStateChanged(
                                    LifecycleOwner unused, Lifecycle.Event event) {
                                if (event != Lifecycle.Event.ON_START) {
                                    return;
                                }
                                View listView = getListView(frag);
                                if (listView == null) {
                                    return;
                                }
                                int paddingBottom = listView.getPaddingBottom();
                                ViewCompat.setOnApplyWindowInsetsListener(
                                        listView,
                                        (v, windowInsets) -> {
                                            Insets insets =
                                                    windowInsets.getInsets(
                                                            WindowInsetsCompat.Type.systemBars());
                                            v.setPadding(
                                                    v.getPaddingLeft(),
                                                    v.getPaddingTop(),
                                                    v.getPaddingRight(),
                                                    paddingBottom + insets.bottom);
                                            return WindowInsetsCompat.CONSUMED;
                                        });
                            }
                        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        maybeRedirectIfDisabled();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        // We don't set configChanges, but small screen size changes may still be delivered here.
        super.onConfigurationChanged(newConfig);
        configureHomeButton();
    }

    /** Decide whether a home/back button should be shown or not. */
    private void configureHomeButton() {
        ActionBar actionBar = getActionBar();
        Fragment frag =
                getSupportFragmentManager()
                        .findFragmentById(
                                com.android.settingslib.collapsingtoolbar.R.id.content_frame);
        if (actionBar == null || frag == null) {
            return;
        }

        // Only the homepage can be considered a "second layer" page as it's the only one that
        // can be reached from the Settings menu. The other pages are only reachable using
        // a direct intent (e.g. notification, "first layer") and/or by navigating within Safety
        // Center ("third layer").
        // Note that the homepage can also be a "first layer" page, but that would only happen
        // if the activity is not embedded.
        boolean isSecondLayerPage = frag instanceof SafetyCenterScrollWrapperFragment;
        if (ActivityEmbeddingUtils.shouldHideNavigateUpButton(this, isSecondLayerPage)) {
            actionBar.setDisplayHomeAsUpEnabled(false);
            actionBar.setHomeButtonEnabled(false);
        }
    }

    private boolean maybeRedirectIfDisabled() {
        if (mSafetyCenterManager == null || !mSafetyCenterManager.isSafetyCenterEnabled()) {
            Log.w(TAG, "Safety Center disabled, redirecting to settings page");
            startActivity(
                    new Intent(getActionToRedirectWhenDisabled())
                            .addFlags(FLAG_ACTIVITY_FORWARD_RESULT));
            finish();
            return true;
        }
        return false;
    }

    private String getActionToRedirectWhenDisabled() {
        boolean isPrivacyControls =
                TextUtils.equals(getIntent().getAction(), PRIVACY_CONTROLS_ACTION);
        if (isPrivacyControls) {
            return Settings.ACTION_PRIVACY_SETTINGS;
        }
        return Settings.ACTION_SETTINGS;
    }

    private boolean maybeRedirectIntoTwoPaneSettings() {
        return shouldUseTwoPaneSettings() && tryRedirectTwoPaneSettings();
    }

    private boolean shouldUseTwoPaneSettings() {
        if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this)) {
            return false;
        }

        Bundle extras = getIntent().getExtras();
        if (extras != null && extras.getBoolean(EXTRA_PREVENT_TRAMPOLINE_TO_SETTINGS, false)) {
            return false;
        }

        return isTaskRoot() && !ActivityEmbeddingUtils.isActivityEmbedded(this);
    }

    /** Return {@code true} if the redirection was attempted. */
    private boolean tryRedirectTwoPaneSettings() {
        Intent twoPaneIntent = getTwoPaneIntent();
        if (twoPaneIntent == null) {
            return false;
        }

        Log.i(TAG, "Safety Center restarting in Settings two-pane layout");
        startActivity(twoPaneIntent);
        finishAndRemoveTask();
        return true;
    }

    @Nullable
    private Intent getTwoPaneIntent() {
        Intent twoPaneIntent = ActivityEmbeddingUtils.buildEmbeddingActivityBaseIntent(this);
        if (twoPaneIntent == null) {
            return null;
        }

        twoPaneIntent.putExtras(getIntent());
        twoPaneIntent.putExtra(
                EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI,
                getIntent().toUri(Intent.URI_INTENT_SCHEME));
        twoPaneIntent.putExtra(
                EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY, MENU_KEY_SAFETY_CENTER);
        return twoPaneIntent;
    }

    private void logPrivacySourceMetric() {
        Intent intent = getIntent();
        if (intent != null && intent.hasExtra(Constants.EXTRA_PRIVACY_SOURCE)) {
            int privacySource = intent.getIntExtra(Constants.EXTRA_PRIVACY_SOURCE, -1);
            int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
            long sessionId =
                    intent.getLongExtra(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID);
            Log.i(
                    TAG,
                    "privacy source notification metric, source "
                            + privacySource
                            + " uid "
                            + uid
                            + " sessionId "
                            + sessionId);
            PermissionControllerStatsLog.write(
                    PRIVACY_SIGNAL_NOTIFICATION_INTERACTION,
                    privacySource,
                    uid,
                    PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__NOTIFICATION_CLICKED,
                    sessionId);
        }
    }

    private Fragment openHomepage() {
        logPrivacySourceMetric();
        setTitle(getString(R.string.safety_center_dashboard_page_title));
        return new SafetyCenterScrollWrapperFragment();
    }

    @RequiresApi(UPSIDE_DOWN_CAKE)
    private Fragment openRelevantSubpage(String groupId) {
        if (groupId.isEmpty()) {
            return openHomepage();
        }

        long sessionId = Utils.getOrGenerateSessionId(getIntent());
        if (Objects.equals(groupId, PRIVACY_SOURCES_GROUP_ID)) {
            logPrivacySourceMetric();
            return PrivacySubpageFragment.newInstance(sessionId);
        }

        return SafetyCenterSubpageFragment.newInstance(sessionId, groupId);
    }

    @RequiresApi(UPSIDE_DOWN_CAKE)
    private String getParentGroupId(String preferenceKey) {
        if (Pref.findByKey(preferenceKey) != null) {
            return PRIVACY_SOURCES_GROUP_ID;
        }

        SafetyCenterConfig safetyCenterConfig = mSafetyCenterManager.getSafetyCenterConfig();
        String[] splitKey;
        if (preferenceKey.endsWith(PERSONAL_PROFILE_SUFFIX)) {
            splitKey = preferenceKey.split("_" + PERSONAL_PROFILE_SUFFIX);
        } else if (preferenceKey.endsWith(WORK_PROFILE_SUFFIX)) {
            splitKey = preferenceKey.split("_" + WORK_PROFILE_SUFFIX);
        } else if (preferenceKey.endsWith(PRIVATE_PROFILE_SUFFIX)) {
            splitKey = preferenceKey.split("_" + PRIVATE_PROFILE_SUFFIX);
        } else {
            return "";
        }

        if (safetyCenterConfig == null || splitKey.length == 0) {
            return "";
        }

        List<SafetySourcesGroup> groups = safetyCenterConfig.getSafetySourcesGroups();
        for (SafetySourcesGroup group : groups) {
            if (group.getType() != SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL) {
                // Hidden and static groups are not opened in a subpage.
                continue;
            }
            for (SafetySource source : group.getSafetySources()) {
                if (Objects.equals(source.getId(), splitKey[0])) {
                    return group.getId();
                }
            }
        }
        return "";
    }

    @Nullable
    private View getListView(Fragment fragment) {
        if (fragment instanceof PreferenceFragmentCompat) {
            return ((PreferenceFragmentCompat) fragment).getListView();
        }
        if (fragment instanceof SafetyCenterScrollWrapperFragment) {
            Fragment dashboardFragment =
                    fragment.getChildFragmentManager().findFragmentById(R.id.fragment_container);
            if (dashboardFragment instanceof PreferenceFragmentCompat) {
                return ((PreferenceFragmentCompat) dashboardFragment).getListView();
            }
        }
        return null;
    }
}
