/*
 * Copyright (C) 2023 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.systemui.car.displaycompat;

import static android.car.Car.PERMISSION_MANAGE_DISPLAY_COMPATIBILITY;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;

import static com.android.systemui.car.displaycompat.CarDisplayCompatUtils.getPackageName;
import static com.android.systemui.car.displaycompat.CarDisplayCompatUtils.requiresDisplayCompat;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
import android.car.content.pm.CarPackageManager;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerGlobal;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;

import androidx.annotation.MainThread;
import androidx.annotation.RequiresPermission;

import com.android.systemui.R;
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;

import javax.inject.Inject;

/**
 * Implementation of {@link ToolbarController} for showing/hiding the display compatibility toolbar.
 */
public class ToolbarControllerImpl implements ToolbarController {

    private static final String TAG = ToolbarControllerImpl.class.getSimpleName();

    private ViewGroup mToolbarParent;

    @NonNull
    private final Handler mMainHandler;

    @NonNull
    private CarServiceProvider mCarServiceProvider;
    @Nullable
    private CarPackageManager mCarPackageManager;
    @NonNull
    @UiBackground
    private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener =
            car -> {
                mCarPackageManager = car.getCarManager(CarPackageManager.class);
            };
    @Nullable
    private ImageButton mBackButton;

    @Inject
    public ToolbarControllerImpl(
            @NonNull @Main Handler mainHandler,
            CarServiceProvider carServiceProvider
    ) {
        mMainHandler = mainHandler;
        mCarServiceProvider = carServiceProvider;
    }

    /**
     * Needs to be called before calling any other method.
     */
    @Override
    public void init(@NonNull ViewGroup parent) {
        mToolbarParent = parent;
        mCarServiceProvider.addListener(mCarServiceLifecycleListener);
    }

    @MainThread
    @Override
    public void show() {
        if (mToolbarParent == null) {
            Log.w(TAG, "init was not called");
            return;
        }
        if (mBackButton == null) {
            // Can't do this in init method because that's called when the window is available way
            // before the views are inflated.
            mBackButton = mToolbarParent.findViewById(R.id.back_btn);
            if (mBackButton != null) {
                mBackButton.setOnClickListener(v -> {
                    sendVirtualBackPress();
                });
            }
        }
        mToolbarParent.setVisibility(VISIBLE);
        View actionBar = mToolbarParent.findViewById(R.id.action_bar);
        if (actionBar != null) {
            actionBar.setVisibility(VISIBLE);
        }
    }

    @MainThread
    @Override
    public void hide() {
        if (mToolbarParent == null) {
            Log.w(TAG, "init was not called");
            return;
        }
        mToolbarParent.setVisibility(GONE);
        View actionBar = mToolbarParent.findViewById(R.id.action_bar);
        if (actionBar != null) {
            actionBar.setVisibility(GONE);
        }
    }

    @RequiresPermission(allOf = {PERMISSION_MANAGE_DISPLAY_COMPATIBILITY,
            android.Manifest.permission.QUERY_ALL_PACKAGES})
    @Override
    public void update(@NonNull RunningTaskInfo taskInfo) {
        if (mToolbarParent == null) {
            Log.w(TAG, "init was not called");
            return;
        }
        if (requiresDisplayCompat(
                getPackageName(taskInfo), taskInfo.userId, mCarPackageManager)
                && taskInfo.displayId == DEFAULT_DISPLAY) {
            mMainHandler.post(() -> show());
            return;
        }
        mMainHandler.post(() -> hide());
    }

    /**
     * Send both action down and up to be qualified as a back press. Set time for key events, so
     * they are not staled.
     */
    public static void sendVirtualBackPress() {
        long downEventTime = SystemClock.uptimeMillis();
        long upEventTime = downEventTime + 1;

        final KeyEvent keydown = new KeyEvent(downEventTime, downEventTime, KeyEvent.ACTION_DOWN,
                KeyEvent.KEYCODE_BACK, /* repeat= */ 0, /* metaState= */ 0,
                KeyCharacterMap.VIRTUAL_KEYBOARD, /* scancode= */ 0, KeyEvent.FLAG_FROM_SYSTEM);
        final KeyEvent keyup = new KeyEvent(upEventTime, upEventTime, KeyEvent.ACTION_UP,
                KeyEvent.KEYCODE_BACK, /* repeat= */ 0, /* metaState= */ 0,
                KeyCharacterMap.VIRTUAL_KEYBOARD, /* scancode= */ 0, KeyEvent.FLAG_FROM_SYSTEM);

        InputManagerGlobal inputManagerGlobal = InputManagerGlobal.getInstance();
        inputManagerGlobal.injectInputEvent(keydown, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
        inputManagerGlobal.injectInputEvent(keyup, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
    }
}
