/*
 * 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.launcher3.taskbar.allapps;

import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_TASKBAR_ALL_APPS;
import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;

import androidx.annotation.Nullable;

import com.android.internal.jank.Cuj;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.allapps.AllAppsTransitionListener;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.appprediction.AppsDividerView;
import com.android.launcher3.taskbar.NavbarButtonsViewController;
import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.taskbar.TaskbarSharedState;
import com.android.launcher3.taskbar.TaskbarStashController;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;

import java.util.Optional;

/**
 * Handles the {@link TaskbarAllAppsContainerView} behavior and synchronizes its transitions with
 * taskbar stashing.
 */
final class TaskbarAllAppsViewController {

    private final TaskbarOverlayContext mContext;
    private final TaskbarAllAppsSlideInView mSlideInView;
    private final TaskbarAllAppsContainerView mAppsView;
    private final TaskbarStashController mTaskbarStashController;
    private final NavbarButtonsViewController mNavbarButtonsViewController;
    private final TaskbarOverlayController mOverlayController;
    private final @Nullable TaskbarSharedState mTaskbarSharedState;
    private final boolean mShowKeyboard;

    TaskbarAllAppsViewController(
            TaskbarOverlayContext context,
            TaskbarAllAppsSlideInView slideInView,
            TaskbarControllers taskbarControllers,
            TaskbarSearchSessionController searchSessionController,
            boolean showKeyboard) {

        mContext = context;
        mSlideInView = slideInView;
        mAppsView = mSlideInView.getAppsView();
        mTaskbarStashController = taskbarControllers.taskbarStashController;
        mNavbarButtonsViewController = taskbarControllers.navbarButtonsViewController;
        mOverlayController = taskbarControllers.taskbarOverlayController;
        mTaskbarSharedState = taskbarControllers.getSharedState();
        mShowKeyboard = showKeyboard;

        mSlideInView.init(new TaskbarAllAppsCallbacks(searchSessionController));
        setUpAppDivider();
        setUpTaskbarStashing();
    }

    /** Starts the {@link TaskbarAllAppsSlideInView} enter transition. */
    void show(boolean animate) {
        mSlideInView.show(animate);
    }

    /** Closes the {@link TaskbarAllAppsSlideInView}. */
    void close(boolean animate) {
        mSlideInView.close(animate);
    }

    private void setUpAppDivider() {
        mAppsView.getFloatingHeaderView()
                .findFixedRowByType(AppsDividerView.class)
                .setShowAllAppsLabel(!ALL_APPS_VISITED_COUNT.hasReachedMax(mContext));
        ALL_APPS_VISITED_COUNT.increment(mContext);
    }

    private void setUpTaskbarStashing() {
        if (mContext.isTransientTaskbar()) {
            mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, true);
            mTaskbarStashController.applyState();
        }

        Optional.ofNullable(mTaskbarSharedState).ifPresent(s -> s.allAppsVisible = true);
        mNavbarButtonsViewController.setSlideInViewVisible(true);
        mSlideInView.setOnCloseBeginListener(() -> {
            Optional.ofNullable(mTaskbarSharedState).ifPresent(s -> s.allAppsVisible = false);
            mNavbarButtonsViewController.setSlideInViewVisible(false);
            AbstractFloatingView.closeOpenContainer(
                    mContext, AbstractFloatingView.TYPE_ACTION_POPUP);

            if (mContext.isTransientTaskbar()) {
                mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, false);
                mTaskbarStashController.applyState();
            }
        });
    }

    class TaskbarAllAppsCallbacks implements AllAppsTransitionListener {
        private final TaskbarSearchSessionController mSearchSessionController;

        private TaskbarAllAppsCallbacks(TaskbarSearchSessionController searchSessionController) {
            mSearchSessionController = searchSessionController;
        }

        int getOpenDuration() {
            return mOverlayController.getOpenDuration();
        }

        int getCloseDuration() {
            return mOverlayController.getCloseDuration();
        }

        @Override
        public void onAllAppsTransitionStart(boolean toAllApps) {
            mSearchSessionController.onAllAppsTransitionStart(toAllApps);
        }

        @Override
        public void onAllAppsTransitionEnd(boolean toAllApps) {
            mSearchSessionController.onAllAppsTransitionEnd(toAllApps);
            if (toAllApps
                    && mShowKeyboard
                    && mAppsView.getSearchUiManager().getEditText() != null) {
                mAppsView.getSearchUiManager().getEditText().requestFocus();
            }
            if (toAllApps) {
                InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS);
            }
        }

        /** Check if search session can handle back. This check doesn't perform any action. */
        boolean canHandleSearchBackInvoked() {
            return mSearchSessionController.canHandleBackInvoked();
        }

        /** Invoked on back press, returning {@code true} if the search session handled it. */
        boolean handleSearchBackInvoked() {
            return mSearchSessionController.handleBackInvoked();
        }

        void onAllAppsAnimationPending(PendingAnimation animation, boolean toAllApps) {
            mSearchSessionController.onAllAppsAnimationPending(animation, toAllApps, mShowKeyboard);
        }
    }
}
